# handles server side table processing


class ServerSideTable:
    """
        This class is used to do server-side processing
        on the DataTables table such as paginating, sorting,
        filtering(not implemented) etc. This takes the load off
        the client-side and reduces the size of data interchanged.

        Usage:
            ServerSideTable(rows_count, table_rows, header_data_names, request_values)
        where,
            `rows_count` as number of rows in the table,
            `table_rows` as data rows of the table,
            `header_data_names` as headers names of the table.
            `request_values` must have request arguments values
            including the DataTables server-side processing arguments.

        Have a look at snp_browser_table() function in 
        wqflask/wqflask/views.py for reference use.
    """

    def __init__(self, rows_count, table_rows, header_data_names, request_values):
        self.request_values = request_values
        self.sEcho = self.request_values['sEcho']

        self.rows_count = rows_count
        self.table_rows = table_rows
        self.header_data_names = header_data_names

        self.sort_rows()
        self.paginate_rows()

    def sort_rows(self):
        """
        Sorts the rows taking in to account the column (or columns) that the
        user has selected.
        """
        def is_reverse(str_direction):
            """ Maps the 'desc' and 'asc' words to True or False. """
            return True if str_direction == 'desc' else False

        if (self.request_values['iSortCol_0'] != "") and (int(self.request_values['iSortingCols']) > 0):
            for i in range(0, int(self.request_values['iSortingCols'])):
                column_number = int(self.request_values['iSortCol_' + str(i)])
                column_name = self.header_data_names[column_number - 1]
                sort_direction = self.request_values['sSortDir_' + str(i)]
                self.table_rows = sorted(self.table_rows,
                                         key=lambda x: x[column_name],
                                         reverse=is_reverse(sort_direction))

    def paginate_rows(self):
        """
        Selects a subset of the filtered and sorted data based on if the table
        has pagination, the current page and the size of each page.
        """
        def requires_pagination():
            """ Check if the table is going to be paginated """
            if self.request_values['iDisplayStart'] != "":
                if int(self.request_values['iDisplayLength']) != -1:
                    return True
            return False

        if not requires_pagination():
            return

        start = int(self.request_values['iDisplayStart'])
        length = int(self.request_values['iDisplayLength'])

        # if search returns only one page
        if len(self.table_rows) <= length:
            # display only one page
            self.table_rows = self.table_rows[start:]
        else:
            limit = -len(self.table_rows) + start + length
            if limit < 0:
                # display pagination
                self.table_rows = self.table_rows[start:limit]
            else:
                # display last page of pagination
                self.table_rows = self.table_rows[start:]

    def get_page(self):
        output = {}
        output['sEcho'] = str(self.sEcho)
        output['iTotalRecords'] = str(float('Nan'))
        output['iTotalDisplayRecords'] = str(self.rows_count)
        output['data'] = self.table_rows
        return output
