class FileUploadHelper(QDialog):

    # settings
    kegg_domain = 'KEGG'

    supported_domains = OrderedDict({
        'Gene Ontology': gene_ontology_domain,
        'Gene Sets': gene_sets_domain
    })

    supported_organisms = [
        common_taxid_to_name(tax_id) for tax_id in common_taxids()
    ]

    hierarchies = {
        'GO - Biological Process': ('GO', 'biological_process'),
        'GO - Molecular Function': ('GO', 'molecular_function'),
        'GO - Cellular Component': ('GO', 'cellular_component'),
        'KEGG - Pathways': ('KEGG', 'pathways'),
        'KEGG - Orthologs': ('KEGG', 'orthologs')
    }

    def __init__(self, parent=None):
        super(FileUploadHelper, self).__init__(
            parent, Qt.Window | Qt.WindowTitleHint | Qt.CustomizeWindowHint
            | Qt.WindowCloseButtonHint | Qt.WindowMaximizeButtonHint)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setWindowTitle('Add new file')

        self.info_state = INFO_FILE_SCHEMA
        self.layout = QVBoxLayout(self)

        # domain selection combobox
        self.domain_selection = QComboBox()
        self.domain_selection.addItems(self.supported_domains.keys())
        self.domain_selection.currentIndexChanged.connect(
            self.__on_domain_selection)
        self.__create_selection_row('Domain: ', self.domain_selection)

        # domain selection combobox
        self.hierarchy_selection = QComboBox()
        self.hierarchy_selection.addItems(self.hierarchies.keys())
        self.layout.addWidget(self.hierarchy_selection,
                              alignment=Qt.AlignVCenter)
        self.__on_domain_selection()

        # select organism
        self.organism_selection = QComboBox()
        self.organism_selection.addItems(self.supported_organisms)
        self.__create_selection_row('Organism: ', self.organism_selection)

        # title
        self.line_edit_title = QLineEdit()
        self.__create_selection_row('Title: ', self.line_edit_title)

        # tags
        self.line_edit_tags = QLineEdit()
        self.__create_selection_row('Tags (comma-separated): ',
                                    self.line_edit_tags)

        # file selector
        self.file_info = QLabel()
        self.file_select_btn = QPushButton('Select File', self)
        self.file_select_btn.clicked.connect(self.__handle_file_selector)
        self.__create_selection_row(' ', self.file_select_btn)

        # add file info section
        self.layout.addWidget(self.file_info, alignment=Qt.AlignCenter)

        self.layout.addStretch(1)

        # Ok and Cancel buttons
        self.buttons = QDialogButtonBox(
            QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        self.layout.addWidget(self.buttons, alignment=Qt.AlignJustify)

        self.buttons.accepted.connect(self.__accept)
        self.buttons.rejected.connect(self.__close)

        # path to a selected file
        self.file_path = None

    def __on_domain_selection(self):
        selected = self.__get_selected_domain() == gene_sets_domain
        self.hierarchy_selection.setVisible(selected)

    def __get_selected_domain(self):
        domain_label = list(self.supported_domains.keys())[
            self.domain_selection.currentIndex()]
        return self.supported_domains[domain_label]

    def __get_selected_hier(self):
        hier_label = list(
            self.hierarchies.keys())[self.hierarchy_selection.currentIndex()]
        return self.hierarchies[hier_label]

    def __create_selection_row(self, label, widget):
        self.layout.addWidget(QLabel(label), alignment=Qt.AlignLeft)
        self.layout.addWidget(widget, alignment=Qt.AlignVCenter)

    def __accept(self):
        if self.file_path:
            self.info_state = self.__parse_selection()
            self.__move_to_serverfiles_folder(self.file_path)

            self.parent().initialize_files_view()
            self.close()

    def __close(self):
        self.close()

    def closeEvent(self, event):
        # clean-up
        self.parent()._dialog = None

    def __filename(self, domain, organism):
        """ Create filename based od domain name and organism.
        """

        if domain in self.supported_domains.values(
        ) and domain == gene_ontology_domain and organism:
            return FILENAME_ANNOTATION.format(organism)

        elif domain in self.supported_domains.values(
        ) and domain == gene_sets_domain and organism:
            return filename((self.__get_selected_hier()), organism)

    def __parse_selection(self):
        try:
            domain = self.__get_selected_domain()
            organism = taxname_to_taxid(self.supported_organisms[
                self.organism_selection.currentIndex()])
        except KeyError as e:
            raise e

        return {
            'domain': domain,
            'organism': organism,
            'filename': self.__filename(domain, organism),
            'title': self.line_edit_title.text(),
            'tags': self.line_edit_tags.text().split(','),
            'source': SOURCE_USER
        }

    def __move_to_serverfiles_folder(self, selected_file_path):
        domain_path = serverfiles.localpath(self.info_state['domain'])
        file_path = os.path.join(domain_path, self.info_state['filename'])
        create_folder(domain_path)

        try:
            copyfile(selected_file_path, file_path)
        except IOError as e:
            # TODO: handle error properly
            raise e

        # if copy successful create .info file
        create_info_file(file_path, **self.info_state)

    def __handle_file_selector(self):
        self.file_path = QFileDialog.getOpenFileName(self, 'Open File')[0]
        self.file_info.setText('Selected File: {}'.format(
            os.path.basename(self.file_path)))