from window import Window
from windowstringreader import WindowStringReader
from partitionpane import PartitionPane
from readmultext import ReadMulText
from confirmwindow import ConfirmWindow
from actionresult import ActionResult
from device import Device

class CustomPartition(object):
    def __init__(self, maxy, maxx, install_config):
        self.maxx = maxx
        self.maxy = maxy
        self.win_width = maxx - 4
        self.win_height = maxy - 4
        self.install_config = install_config
        self.path_checker = []

        self.win_starty = (self.maxy - self.win_height) // 2
        self.win_startx = (self.maxx - self.win_width) // 2

        self.text_starty = self.win_starty + 4
        self.text_height = self.win_height - 6
        self.text_width = self.win_width - 6
        self.cp_config = {}
        self.cp_config['partitionsnumber'] = 0
        self.devices = Device.refresh_devices_bytes()
        self.has_slash = False
        self.has_remain = False
        self.has_empty = False

        self.disk_size = []
        self.disk_to_index = {}
        for index, device in enumerate(self.devices):
            self.disk_size.append((device.path, int(device.size) / 1048576))
            self.disk_to_index[device.path] = index

        self.window = Window(self.win_height, self.win_width, self.maxy, self.maxx,
                             'Welcome to the Photon installer', False, can_go_next=False)
        Device.refresh_devices()

    def display(self):
        if 'autopartition' in self.install_config and self.install_config['autopartition'] == True:
            return ActionResult(True, None)

        self.device_index = self.disk_to_index[self.install_config['disk']]

        self.disk_buttom_items = []
        self.disk_buttom_items.append(('<Next>', self.next))
        self.disk_buttom_items.append(('<Create New>', self.create_function))
        self.disk_buttom_items.append(('<Delete All>', self.delete_function))
        self.disk_buttom_items.append(('<Go Back>', self.go_back))

        self.text_items = []
        self.text_items.append(('Disk', 20))
        self.text_items.append(('Size', 5))
        self.text_items.append(('Type', 5))
        self.text_items.append(('Mountpoint', 20))
        self.table_space = 5

        title = 'Current partitions:\n'
        self.window.addstr(0, (self.win_width - len(title)) // 2, title)

        info = ("Unpartitioned space: " +
                str(self.disk_size[self.device_index][1])+
                " MB, Total size: "+
                str(int(self.devices[self.device_index].size)/ 1048576) + " MB")

        self.partition_pane = PartitionPane(self.text_starty, self.maxx, self.text_width,
                                  self.text_height, self.disk_buttom_items,
                                  config=self.cp_config,
                                  text_items=self.text_items, table_space=self.table_space,
                                  info=info,
                                  size_left=str(self.disk_size[self.device_index][1]))

        self.window.set_action_panel(self.partition_pane)

        return self.window.do_action()

    def validate_partition(self, pstr):
        if not pstr:
            return ActionResult(False, None)
        sizedata = pstr[0]
        mtdata = pstr[2]
        typedata = pstr[1]
        devicedata = self.devices[self.device_index].path

        #no empty fields unless swap
        if (typedata == 'swap' and
                (len(mtdata) != 0 or len(typedata) == 0 or len(devicedata) == 0)):
            return False, "invalid swap data "

        if (typedata != 'swap' and
                (len(sizedata) == 0 or
                 len(mtdata) == 0 or
                 len(typedata) == 0 or
                 len(devicedata) == 0)):
            if not self.has_empty and mtdata and typedata and devicedata:
                self.has_empty = True
            else:
                return False, "Input cannot be empty"

        if typedata != 'swap' and typedata != 'ext3' and typedata != 'ext4':
            return False, "Invalid type"

        if len(mtdata) != 0 and mtdata[0] != '/':
            return False, "Invalid path"

        if mtdata in self.path_checker:
            return False, "Path already existed"
        #validate disk: must be one of the existing disks
        i = self.device_index

        #valid size: must not exceed memory limit
        curr_size = self.disk_size[i][1]
        if len(sizedata) != 0:
            try:
                int(sizedata)
            except ValueError:
                return False, "invalid device size"

            if int(curr_size) - int(sizedata) < 0:
                return False, "invalid device size"
            #if valid, update the size and return true
            new_size = (self.disk_size[i][0], int(curr_size)- int(sizedata))
            self.disk_size[i] = new_size

        if mtdata == "/":
            self.has_slash = True

        self.path_checker.append(mtdata)
        return True, None

    def create_function(self):
        self.window.hide_window()

        self.cp_config['partition_disk'] = self.devices[self.device_index].path
        self.partition_items = []
        self.partition_items.append(('Size in MB: ' +
                                     str(self.disk_size[self.device_index][1]) +
                                     ' available'))
        self.partition_items.append(('Type: (ext3, ext4, swap)'))
        self.partition_items.append(('Mountpoint:'))
        self.create_window = ReadMulText(
            self.maxy, self.maxx, 0,
            self.cp_config,
            str(self.cp_config['partitionsnumber']) + 'partition_info',
            self.partition_items,
            None,
            None,
            None,
            self.validate_partition,   #validation function of the input
            None,
            True,
            )
        result = self.create_window.do_action()
        if result.success:
            self.cp_config['partitionsnumber'] = self.cp_config['partitionsnumber'] + 1

        #parse the input in install config
        return self.display()

    def delete_function(self):
        self.delete()
        return self.display()

    def go_back(self):
        self.delete()
        self.window.hide_window()
        self.partition_pane.hide()
        return ActionResult(False, {'goBack':True})

    def next(self):
        if self.cp_config['partitionsnumber'] == 0:
            window_height = 9
            window_width = 40
            window_starty = (self.maxy-window_height) // 2 + 5
            confirm_window = ConfirmWindow(window_height, window_width, self.maxy,
                                           self.maxx, window_starty,
                                           'Partition information cannot be empty',
                                           info=True)
            confirm_window.do_action()
            return self.display()
        #must have /
        if not self.has_slash:
            window_height = 9
            window_width = 40
            window_starty = (self.maxy - window_height) // 2 + 5
            confirm_window = ConfirmWindow(window_height, window_width, self.maxy,
                                           self.maxx, window_starty, 'Missing /',
                                           info=True)
            confirm_window.do_action()
            return self.display()

        self.window.hide_window()
        self.partition_pane.hide()

        partitions = []
        for i in range(int(self.cp_config['partitionsnumber'])):
            if len(self.cp_config[str(i)+'partition_info'+str(0)]) == 0:
                sizedata = 0
            else:
                sizedata = int(self.cp_config[str(i) + 'partition_info' + str(0)])
            mtdata = self.cp_config[str(i) + 'partition_info' + str(2)]
            typedata = self.cp_config[str(i) + 'partition_info'+str(1)]

            partitions = partitions + [{"mountpoint": mtdata,
                                        "size": sizedata,
                                        "filesystem": typedata},]
        self.install_config['partitions'] = partitions

        return ActionResult(True, {'goNext':True})

    def delete(self):
        for i in range(int(self.cp_config['partitionsnumber'])):
            self.cp_config[str(i)+'partition_info'+str(0)] = ''
            self.cp_config[str(i)+'partition_info'+str(1)] = ''
            self.cp_config[str(i)+'partition_info'+str(2)] = ''
            self.cp_config[str(i)+'partition_info'+str(3)] = ''
        del self.disk_size[:]
        for index, device in enumerate(self.devices):
            self.disk_size.append((device.path, int(device.size) / 1048576))
        del self.path_checker[:]
        self.has_slash = False
        self.has_remain = False
        self.has_empty = False
        self.cp_config['partitionsnumber'] = 0
