#!/usr/bin/env python
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:ai


__license__   = 'GPL v3'
__copyright__ = '2025, Digital Assassins'
__docformat__ = 'restructuredtext en'

if False:
    # This is here to keep my python error checker from complaining about
    # the builtin functions that will be defined by the plugin loading system
    # You do not need this code in your plugins
    get_icons = get_resources = None
try:
    from qt.core import Qt, pyqtSignal, pyqtSlot, QDialog, QLabel, QMessageBox, QPushButton, QVBoxLayout, QProgressBar, QWidget, QComboBox, QHBoxLayout, QPlainTextEdit, QSize, QSizePolicy
except ImportError:
    from PyQt5.Qt import Qt, pyqtSignal, pyqtSlot, QDialog, QLabel, QMessageBox, QPushButton, QVBoxLayout, QProgressBar, QWidget, QComboBox, QHBoxLayout, QPlainTextEdit, QSize, QSizePolicy

from PyQt5 import QtCore, QtGui, QtWidgets

from calibre.constants import DEBUG 
from calibre_plugins.ai_custom_tag_extractor.ui_state import UIState
from calibre_plugins.ai_custom_tag_extractor.job_thread import JobThread
import calibre_plugins.ai_custom_tag_extractor.job_progress_ticker as ticker
import calibre_plugins.ai_custom_tag_extractor.assets.backgrounds
import calibre_plugins.ai_custom_tag_extractor.sqdb_adapter as sqdb
import calibre_plugins.ai_custom_tag_extractor.config as cfg
import time
#from calibre_plugins.ai_custom_tag_extractor.config import plugin_prefs

class MainDialog(QDialog):
    
    COLUMN_WIDGET_VISIBLE_COUNT = 0
    COLUMN_LIST = []
    COLUMN_LIST_COUNT = 0
    COLUMN_UI_REFRESH_COUNT = 0
    ## for progess
    PROGRESS_SINGLE_PERCENT = 0
    PROGRESS_CURRENT_PERCENT = 0
    #@pyqtsignal
    #THREAD_PROGRESS(val:int)
    #THREAD_PROGRESS = pyqtSignal(int, name='threadProgress')
    
    
    def __init__(self, gui, icon, do_user_config, show_review_dialog, show_about_dialog):
        QDialog.__init__(self, gui)
        self.gui = gui
        self.do_user_config = do_user_config
        self.show_review_dialog = show_review_dialog
        self.show_about_dialog = show_about_dialog
        self.EXTRACTION_THREAD = None
        self.sqldbadapter = sqdb.SQliteAdapter()
        self.get_ai_platform()
        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.AI_ANSWERS = {}
        self.TICKER_THREAD = None
        self.DEBUG_ME = False
        
        # The current database shown in the GUI
        # db is an instance of the class LibraryDatabase from db/legacy.py
        # This class has many, many methods that allow you to do a lot of
        # things. For most purposes you should use db.new_api, which has
        # a much nicer interface from db/cache.py
        self.db = gui.current_db
        
        ##########################################################################################################################################
        ##########################################################################################################################################
        ################################################    Graphical User Interface     #########################################################
        ##########################################################################################################################################
        ##########################################################################################################################################
        
        ############## LOAD GUI ICONS FOR THIS WINDOW ########################
        icons = get_icons(['images/plus.png','images/minus.png','images/config.png','images/extract.png', 'images/progress_info.png','images/stop.png','images/info_icon.png'], 'AI Custom Tag Extractor')
        
        
        ##############################################
        self.setObjectName("Dialog")
        self.setWindowIcon(icon)
        
        self.resize(800, 639)
        self.setMinimumSize(QtCore.QSize(0, 0))
        self.setMaximumSize(QtCore.QSize(3840, 2160))
        self.setAutoFillBackground(False)
        
        self.setStyleSheet("QDialog#Dialog{background-image:url(:/images/background_small.png); background-repeat: no-repeat; background-position: bottom left;}")
        self.verticalLayoutMain = QtWidgets.QVBoxLayout(self)
        self.verticalLayoutMain.setContentsMargins(11, 15, 11, 15)
        self.verticalLayoutMain.setSpacing(7)
        self.verticalLayoutMain.setObjectName("verticalLayoutMain")
        
        ##### TOP MENU LAYOUT ########
        self.topMenuLayout = QtWidgets.QHBoxLayout()
        self.topMenuLayout.setSpacing(7)
        self.topMenuLayout.setObjectName("topMenuLayout")
        
        ##### PLUGIN TITLE ########
        self.pluginTitleLabel = QtWidgets.QLabel(self)
        self.pluginTitleLabel.setAutoFillBackground(False)
        self.pluginTitleLabel.setObjectName("pluginTitleLabel")
        self.pluginTitleLabel.setStyleSheet("font-weight:bold; font-size:16px;")
        self.topMenuLayout.addWidget(self.pluginTitleLabel)
        ##### PLUGIN TITLE ########
        
        ##### HEADER SPACER ########
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.topMenuLayout.addItem(spacerItem)
        
        ##### ABOUT BUTTON ########
        self.aboutButton = QtWidgets.QPushButton(self)
        self.aboutButton.setMaximumSize(QtCore.QSize(33, 16777215))
        self.aboutButton.setText("")
        self.aboutButton.setIcon(icons['images/info_icon.png'])
        self.aboutButton.setObjectName("aboutButton")
        self.topMenuLayout.addWidget(self.aboutButton) 
        ##### ABOUT BUTTON ########
        
        ##### CONFIG BUTTON ########
        self.configButton = QtWidgets.QPushButton(self)
        self.configButton.setMaximumSize(QtCore.QSize(33, 16777215))
        self.configButton.setText("")
        self.configButton.setIcon(icons['images/config.png'])
        self.configButton.setObjectName("configButton")
        self.topMenuLayout.addWidget(self.configButton)
        ##### CONFIG BUTTON ########
        
        ##### ADD TAG ########
        self.addTagBtn = QtWidgets.QPushButton(self)
        self.addTagBtn.setIcon(icons['images/plus.png'])
        self.addTagBtn.setObjectName("addTagBtn")
        self.topMenuLayout.addWidget(self.addTagBtn)
        ##### ADD TAG ########        
        self.verticalLayoutMain.addLayout(self.topMenuLayout)
        
        ##### PROMPT LAYOUT ########
        self.promptWidget = QtWidgets.QWidget(self)
        self.promptWidget.setMinimumSize(QtCore.QSize(0, 400))
        self.promptWidget.setObjectName("promptWidget")
        self.verticalLayoutPromptWidget = QtWidgets.QVBoxLayout(self.promptWidget)
        self.verticalLayoutPromptWidget.setContentsMargins(0, 0, 0, 0)
        self.verticalLayoutPromptWidget.setSpacing(7)
        self.verticalLayoutPromptWidget.setObjectName("verticalLayoutPromptWidget")
        self.vPromptLayout = QtWidgets.QVBoxLayout()
        self.vPromptLayout.setContentsMargins(0, 0, 0, 0)
        self.vPromptLayout.setSpacing(7)
        self.vPromptLayout.setObjectName("vPromptLayout")
        
        ##### HEADER LABEL LAYOUT ########
        self.headerLabelLayout = QtWidgets.QHBoxLayout()
        self.headerLabelLayout.setContentsMargins(0, 0, 0, 0)
        self.headerLabelLayout.setSpacing(7)
        self.headerLabelLayout.setObjectName("headerLabelLayout")
        
        ##### HEADER LABEL ########
        self.columnLabel = QtWidgets.QLabel(self.promptWidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.columnLabel.sizePolicy().hasHeightForWidth())
        self.columnLabel.setSizePolicy(sizePolicy)
        self.columnLabel.setMaximumSize(QtCore.QSize(125, 30))
        self.columnLabel.setObjectName("columnLabel")
        self.headerLabelLayout.addWidget(self.columnLabel)
        
        ##### A.I PROMPT LABEL ########
        self.aiPromptLabel = QtWidgets.QLabel(self.promptWidget)
        self.aiPromptLabel.setMaximumSize(QtCore.QSize(16777215, 30))
        self.aiPromptLabel.setObjectName("aiPromptLabel")
        self.headerLabelLayout.addWidget(self.aiPromptLabel)
        self.vPromptLayout.addLayout(self.headerLabelLayout)
        
        
        ##### TAG INPUT WIDGET 0 ########
        self.horizontalLayoutWidget_0 = QtWidgets.QWidget(self.promptWidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.horizontalLayoutWidget_0.sizePolicy().hasHeightForWidth())
        self.horizontalLayoutWidget_0.setSizePolicy(sizePolicy)
        self.horizontalLayoutWidget_0.setMinimumSize(QtCore.QSize(0, 86))
        self.horizontalLayoutWidget_0.setMaximumSize(QtCore.QSize(16777215, 105))
        self.horizontalLayoutWidget_0.setObjectName("horizontalLayoutWidget_0")
        self.verticalLayoutWidget_0 = QtWidgets.QVBoxLayout(self.horizontalLayoutWidget_0)
        self.verticalLayoutWidget_0.setContentsMargins(0, 0, 0, 0)
        self.verticalLayoutWidget_0.setSpacing(7)
        self.verticalLayoutWidget_0.setObjectName("verticalLayoutWidget_0")
        self.hlTagInput_0 = QtWidgets.QHBoxLayout()
        self.hlTagInput_0.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
        self.hlTagInput_0.setContentsMargins(0, 0, 0, 0)
        self.hlTagInput_0.setSpacing(7)
        self.hlTagInput_0.setObjectName("hlTagInput_0")
        self.tagComboBox_0 = QtWidgets.QComboBox(self.horizontalLayoutWidget_0)
        self.tagComboBox_0.setEnabled(True)
        self.tagComboBox_0.setMinimumSize(QtCore.QSize(120, 0))
        self.tagComboBox_0.setCurrentText("")
        self.tagComboBox_0.setObjectName("tagComboBox_0")
        self.hlTagInput_0.addWidget(self.tagComboBox_0)
        
        self.tagPlainText_0 = QtWidgets.QPlainTextEdit(self.horizontalLayoutWidget_0)
        self.tagPlainText_0.setEnabled(True)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.tagPlainText_0.sizePolicy().hasHeightForWidth())
        self.tagPlainText_0.setSizePolicy(sizePolicy)
        self.tagPlainText_0.setMinimumSize(QtCore.QSize(0, 85))
        self.tagPlainText_0.setMaximumSize(QtCore.QSize(16777215, 105))
        self.tagPlainText_0.setStyleSheet("border: 1px solid grey; border-radius: 5px; background-color: palette(base);")
        self.tagPlainText_0.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.tagPlainText_0.setTabChangesFocus(False)
        self.tagPlainText_0.setBackgroundVisible(False)
        self.tagPlainText_0.setObjectName("tagPlainText_0")
        self.hlTagInput_0.addWidget(self.tagPlainText_0)
        self.verticalLayoutWidget_0.addLayout(self.hlTagInput_0)
        self.vPromptLayout.addWidget(self.horizontalLayoutWidget_0)
        
        ##### HORIZONTAL WIDGET 1 ########
        self.horizontalLayoutWidget_1 = QtWidgets.QWidget(self.promptWidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.horizontalLayoutWidget_1.sizePolicy().hasHeightForWidth())
        self.horizontalLayoutWidget_1.setSizePolicy(sizePolicy)
        self.horizontalLayoutWidget_1.setMinimumSize(QtCore.QSize(0, 86))
        self.horizontalLayoutWidget_1.setMaximumSize(QtCore.QSize(16777215, 105))
        self.horizontalLayoutWidget_1.setObjectName("horizontalLayoutWidget_1")
        self.verticalLayoutWidget_1 = QtWidgets.QVBoxLayout(self.horizontalLayoutWidget_1)
        self.verticalLayoutWidget_1.setContentsMargins(0, 0, 0, 0)
        self.verticalLayoutWidget_1.setSpacing(7)
        self.verticalLayoutWidget_1.setObjectName("verticalLayoutWidget_1")
        self.hlTagInput_1 = QtWidgets.QHBoxLayout()
        self.hlTagInput_1.setContentsMargins(0, 0, 0, 0)
        self.hlTagInput_1.setSpacing(7)
        self.hlTagInput_1.setObjectName("hlTagInput_1")
        self.tagComboBox_1 = QtWidgets.QComboBox(self.horizontalLayoutWidget_1)
        self.tagComboBox_1.setEnabled(True)
        self.tagComboBox_1.setMinimumSize(QtCore.QSize(120, 0))
        self.tagComboBox_1.setCurrentText("")
        self.tagComboBox_1.setObjectName("tagComboBox_1")
        self.hlTagInput_1.addWidget(self.tagComboBox_1)
        
        self.tagPlainText_1 = QtWidgets.QPlainTextEdit(self.horizontalLayoutWidget_1)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.tagPlainText_1.sizePolicy().hasHeightForWidth())
        self.tagPlainText_1.setSizePolicy(sizePolicy)
        self.tagPlainText_1.setMinimumSize(QtCore.QSize(0, 85))
        self.tagPlainText_1.setMaximumSize(QtCore.QSize(16777215, 105))
        self.tagPlainText_1.setStyleSheet("border: 1px solid grey; border-radius: 5px; background-color: palette(base);")
        self.tagPlainText_1.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.tagPlainText_1.setObjectName("tagPlainText_1")
        self.hlTagInput_1.addWidget(self.tagPlainText_1)
        self.tagRemoveButton_1 = QtWidgets.QPushButton(self.horizontalLayoutWidget_1)
        self.tagRemoveButton_1.setMinimumSize(QtCore.QSize(30, 0))
        self.tagRemoveButton_1.setMaximumSize(QtCore.QSize(30, 16777215))
        self.tagRemoveButton_1.setText("") 
        self.tagRemoveButton_1.setIcon(icons['images/minus.png'])
        self.tagRemoveButton_1.setObjectName("tagRemoveButton_1")
        self.hlTagInput_1.addWidget(self.tagRemoveButton_1)
        self.verticalLayoutWidget_1.addLayout(self.hlTagInput_1)
        self.vPromptLayout.addWidget(self.horizontalLayoutWidget_1)
        
        ##### HORIZONTAL WIDGET 2 ########
        self.horizontalLayoutWidget_2 = QtWidgets.QWidget(self.promptWidget)
        self.horizontalLayoutWidget_2.setMinimumSize(QtCore.QSize(0, 86))
        self.horizontalLayoutWidget_2.setMaximumSize(QtCore.QSize(16777215, 105))
        self.horizontalLayoutWidget_2.setObjectName("horizontalLayoutWidget_2")
        self.verticalLayoutWidget_2 = QtWidgets.QVBoxLayout(self.horizontalLayoutWidget_2)
        self.verticalLayoutWidget_2.setContentsMargins(0, 0, 0, 0)
        self.verticalLayoutWidget_2.setSpacing(7)
        self.verticalLayoutWidget_2.setObjectName("verticalLayoutWidget_2")
        self.hlTagInput_2 = QtWidgets.QHBoxLayout()
        self.hlTagInput_2.setContentsMargins(0, 0, 0, 0)
        self.hlTagInput_2.setSpacing(7)
        self.hlTagInput_2.setObjectName("hlTagInput_2")
        self.tagComboBox_2 = QtWidgets.QComboBox(self.horizontalLayoutWidget_2)
        self.tagComboBox_2.setEnabled(True)
        self.tagComboBox_2.setMinimumSize(QtCore.QSize(120, 0))
        self.tagComboBox_2.setCurrentText("")
        self.tagComboBox_2.setObjectName("tagComboBox_2")
        self.hlTagInput_2.addWidget(self.tagComboBox_2)
        
        self.tagPlainText_2 = QtWidgets.QPlainTextEdit(self.horizontalLayoutWidget_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.tagPlainText_2.sizePolicy().hasHeightForWidth())
        self.tagPlainText_2.setSizePolicy(sizePolicy)
        self.tagPlainText_2.setMinimumSize(QtCore.QSize(0, 85))
        self.tagPlainText_2.setMaximumSize(QtCore.QSize(16777215, 105))
        self.tagPlainText_2.setStyleSheet("border: 1px solid grey; border-radius: 5px; background-color: palette(base);")
        self.tagPlainText_2.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.tagPlainText_2.setObjectName("tagPlainText_2")
        self.hlTagInput_2.addWidget(self.tagPlainText_2)
        self.tagRemoveButton_2 = QtWidgets.QPushButton(self.horizontalLayoutWidget_2)
        self.tagRemoveButton_2.setMinimumSize(QtCore.QSize(30, 0))
        self.tagRemoveButton_2.setMaximumSize(QtCore.QSize(30, 16777215))
        self.tagRemoveButton_2.setText("")
        self.tagRemoveButton_2.setIcon(icons['images/minus.png'])
        self.tagRemoveButton_2.setObjectName("tagRemoveButton_2")
        self.hlTagInput_2.addWidget(self.tagRemoveButton_2)
        self.verticalLayoutWidget_2.addLayout(self.hlTagInput_2)
        self.vPromptLayout.addWidget(self.horizontalLayoutWidget_2)
        
        ##### HORIZONTAL WIDGET 3 ########
        self.horizontalLayoutWidget_3 = QtWidgets.QWidget(self.promptWidget)
        self.horizontalLayoutWidget_3.setMinimumSize(QtCore.QSize(0, 86))
        self.horizontalLayoutWidget_3.setMaximumSize(QtCore.QSize(16777215, 105))
        self.horizontalLayoutWidget_3.setObjectName("horizontalLayoutWidget_3")
        self.verticalLayoutWidget_3 = QtWidgets.QVBoxLayout(self.horizontalLayoutWidget_3)
        self.verticalLayoutWidget_3.setContentsMargins(0, 0, 0, 0)
        self.verticalLayoutWidget_3.setSpacing(7)
        self.verticalLayoutWidget_3.setObjectName("verticalLayoutWidget_3")
        self.hlTagInput_3 = QtWidgets.QHBoxLayout()
        self.hlTagInput_3.setContentsMargins(0, 0, 0, 0)
        self.hlTagInput_3.setSpacing(7)
        self.hlTagInput_3.setObjectName("hlTagInput_3")
        self.tagComboBox_3 = QtWidgets.QComboBox(self.horizontalLayoutWidget_3)
        self.tagComboBox_3.setEnabled(True)
        self.tagComboBox_3.setMinimumSize(QtCore.QSize(120, 0))
        self.tagComboBox_3.setCurrentText("")
        self.tagComboBox_3.setObjectName("tagComboBox_3")
        self.hlTagInput_3.addWidget(self.tagComboBox_3)
        
        self.tagPlainText_3 = QtWidgets.QPlainTextEdit(self.horizontalLayoutWidget_3)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(1)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.tagPlainText_3.sizePolicy().hasHeightForWidth())
        self.tagPlainText_3.setSizePolicy(sizePolicy)
        self.tagPlainText_3.setMinimumSize(QtCore.QSize(0, 85))
        self.tagPlainText_3.setMaximumSize(QtCore.QSize(16777215, 105))
        self.tagPlainText_3.setStyleSheet("border: 1px solid grey; border-radius: 5px; background-color: palette(base);")
        self.tagPlainText_3.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.tagPlainText_3.setObjectName("tagPlainText_3")
        self.hlTagInput_3.addWidget(self.tagPlainText_3)
        self.tagRemoveButton_3 = QtWidgets.QPushButton(self.horizontalLayoutWidget_3)
        self.tagRemoveButton_3.setMinimumSize(QtCore.QSize(30, 0))
        self.tagRemoveButton_3.setMaximumSize(QtCore.QSize(30, 16777215))
        self.tagRemoveButton_3.setText("")
        self.tagRemoveButton_3.setIcon(icons['images/minus.png'])
        self.tagRemoveButton_3.setObjectName("tagRemoveButton_3")
        self.hlTagInput_3.addWidget(self.tagRemoveButton_3)
        self.verticalLayoutWidget_3.addLayout(self.hlTagInput_3)
        self.vPromptLayout.addWidget(self.horizontalLayoutWidget_3)
        ##### HORIZONTAL WIDGET 3 ########
        
        ##### SPACER WIDGET ########
        spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
        self.vPromptLayout.addItem(spacerItem1)
        
        ##### END PROMPT WIDGETS ########
        self.verticalLayoutPromptWidget.addLayout(self.vPromptLayout)
        self.verticalLayoutMain.addWidget(self.promptWidget)
        ##### END PROMPT WIDGETS ########
        
        ##### ACTIONS LAYOUT ########
        self.actionsVLayout = QtWidgets.QVBoxLayout()
        self.actionsVLayout.setContentsMargins(0, 0, 0, 0)
        self.actionsVLayout.setSpacing(7)
        self.actionsVLayout.setObjectName("actionsVLayout")
        
        ####### PROGRESS ###########
        self.progressStatusLabel = QtWidgets.QLabel(self)
        self.progressStatusLabel.setStyleSheet("font-weight: bold;")
        self.progressStatusLabel.setObjectName("progressStatusLabel")
        self.actionsVLayout.addWidget(self.progressStatusLabel)        
        
        ##### ACTIONS HORIZONTAL ########
        self.actionsHLayout = QtWidgets.QHBoxLayout()
        self.actionsHLayout.setContentsMargins(0, 0, 0, 0)
        self.actionsHLayout.setSpacing(7)
        self.actionsHLayout.setObjectName("actionsHLayout")
        
        ####### PROGRESS BAR ###########
        self.mainProgressBar = QtWidgets.QProgressBar(self)
        self.mainProgressBar.setProperty("value", 50)
        self.mainProgressBar.setInvertedAppearance(False)
        self.mainProgressBar.setObjectName("mainProgressBar")
        self.actionsHLayout.addWidget(self.mainProgressBar)
        ####### PROGRESS BAR ###########
        
        ####### SPACER ###########
        spacerItem2 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
        self.actionsHLayout.addItem(spacerItem2)
        ####### SPACER ###########
        
        ########## STOP BUTTON ##########
        self.stopButton = QtWidgets.QPushButton(self)
        self.stopButton.setMaximumSize(QtCore.QSize(33, 16777215))
        self.stopButton.setText("")        
        self.stopButton.setIcon(icons['images/stop.png'])
        self.stopButton.setObjectName("stopButton")
        self.actionsHLayout.addWidget(self.stopButton)
        ########## STOP BUTTON ##########
        
        ####### REVIEW BUTTON ###########
        self.reviewButton = QtWidgets.QPushButton(self)
        self.reviewButton.setMaximumSize(QtCore.QSize(33, 16777215))
        self.reviewButton.setText("")        
        self.reviewButton.setIcon(icons['images/progress_info.png'])
        self.reviewButton.setObjectName("reviewButton")
        self.actionsHLayout.addWidget(self.reviewButton)
        ####### REVIEW BUTTON ###########
        
        ########## EXTRACT TAGS BUTTON ##########
        self.extractTagsBtn = QtWidgets.QPushButton(self)
        self.extractTagsBtn.setMinimumSize(QtCore.QSize(0, 0))
        self.extractTagsBtn.setMaximumSize(QtCore.QSize(105, 16777215))        
        self.extractTagsBtn.setIcon(icons['images/extract.png'])
        self.extractTagsBtn.setObjectName("extractTagsBtn")
        self.actionsHLayout.addWidget(self.extractTagsBtn, alignment=QtCore.Qt.AlignRight)
        ########## EXTRACT TAGS BUTTON ##########
        self.actionsVLayout.addLayout(self.actionsHLayout)
        
        ########## Sub Progress Label ##########
        self.progressSubStatusLabel = QtWidgets.QLabel(self)
        self.progressSubStatusLabel.setStyleSheet("font-weight: bold;")
        self.progressSubStatusLabel.setObjectName("progressSubStatusLabel")
        self.actionsVLayout.addWidget(self.progressSubStatusLabel)
        ########## Sub Progress Label ##########
        
        self.verticalLayoutMain.addLayout(self.actionsVLayout)
        ##### END ACTIONS LAYOUT ########
        
        ##### FOOTER LAYOUT ########
        self.footerLayout = QtWidgets.QHBoxLayout()
        self.footerLayout.setContentsMargins(0, 10, 0, 0)
        self.footerLayout.setSpacing(7)
        self.footerLayout.setObjectName("footerLayout")
        
        ####### DESIGNED BY ###########
        self.designedByLabel = QtWidgets.QLabel(self)
        self.designedByLabel.setObjectName("designedByLabel")
        self.footerLayout.addWidget(self.designedByLabel)
        ####### DESIGNED BY ###########
        
        ####### SPACER ###########
        spacerItem3 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
        self.footerLayout.addItem(spacerItem3)
        ####### SPACER ###########
        
        ####### POWERED BY ###########
        self.poweredByLabel = QtWidgets.QLabel(self)
        self.poweredByLabel.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
        self.poweredByLabel.setWordWrap(False)
        self.poweredByLabel.setOpenExternalLinks(True)
        self.poweredByLabel.setObjectName("poweredByLabel")
        ####### POWERED BY ###########
        
        self.footerLayout.addWidget(self.poweredByLabel)
        self.verticalLayoutMain.addLayout(self.footerLayout)
        ##### END FOOTER LAYOUT ########
        
        ##### checkbox to listen to open review dialog #####
        self.reviewDialogCheckbox = QtWidgets.QCheckBox(self)
        self.reviewDialogCheckbox.setText("")
        self.reviewDialogCheckbox.setObjectName("reviewDialog")
        self.reviewDialogCheckbox.setMaximumSize(0, 0)
        self.reviewDialogCheckbox.stateChanged.connect(self.extract_complete_open_dialog)
        self.verticalLayoutMain.addWidget(self.reviewDialogCheckbox)

        self.retranslateUi(self)
        
        # Set the current index of each combo box
        self.tagComboBox_0.setCurrentIndex(-1)
        self.tagComboBox_1.setCurrentIndex(-1)
        self.tagComboBox_2.setCurrentIndex(-1)
        self.tagComboBox_3.setCurrentIndex(-1)
        
        # Connect the slots for pyqtSlot/pyqtSignal     
        QtCore.QMetaObject.connectSlotsByName(self)
        
        # we hide the the prompt widgets we don't need
        self.horizontalLayoutWidget_1.setVisible(False)
        self.horizontalLayoutWidget_2.setVisible(False)
        self.horizontalLayoutWidget_3.setVisible(False)
        
        # we also hide the progress bar until we need it
        self.mainProgressBar.setVisible(False)
        self.stopButton.setVisible(False)
        self.reviewButton.setVisible(False)
        
        #### update the combo boxes
        self.add_columns_to_combo(self.tagComboBox_0)
        self.add_columns_to_combo(self.tagComboBox_1)
        self.add_columns_to_combo(self.tagComboBox_2)
        self.add_columns_to_combo(self.tagComboBox_3)
        
        #### add the ability to buttons
        self.aboutButton.clicked.connect(self.show_about_dialog)
        self.configButton.clicked.connect(self.config)
        self.addTagBtn.clicked.connect(self.add_column_entry_form)
        
        self.stopButton.clicked.connect(self.stop_extracting)
        self.reviewButton.clicked.connect(self.open_review_dialog)
        
        if self.DEBUG_ME == True:
            self.extractTagsBtn.clicked.connect(self.gui_debug)
        else:
            self.extractTagsBtn.clicked.connect(self.extract_tags)
        
        ### add the ability to remove column
        self.tagRemoveButton_1.clicked.connect(self.remove_column_entry_form)
        self.tagRemoveButton_2.clicked.connect(self.remove_column_entry_form)
        self.tagRemoveButton_3.clicked.connect(self.remove_column_entry_form)
        
        ## now we load the fields saved when the window is closed
        self.load_fields_from_file()
        
        ##########################################################################################################################################
        ##########################################################################################################################################
        ##########################################################################################################################################
        ##########################################################################################################################################
        ##########################################################################################################################################        
        
    def update_ticker(self, update):
        self.TICKER_THREAD.add_to_progress_ticker(update)
        return
        
    def get_ai_platform(self):
        self.AI_PLATFORM = cfg.plugin_prefs[cfg.STORE_NAME][cfg.KEY_AI_PLATFORM]
    
    def get_id_of_selected_in_combo_from_combo_text(self, text):
        for row in self.COLUMN_LIST:            
            if self.COLUMN_LIST[row]['name'] == text:
                return int(self.COLUMN_LIST[row]['id'])
        else:
            return 0
    
    def get_index_of_selected_in_combo_from_combo_text(self, text):
        for row in self.COLUMN_LIST:            
            if self.COLUMN_LIST[row]['name'] == text:
                return int(self.COLUMN_LIST[row]['index'])
        else:
            return 0
            
    def get_label_of_selected_in_combo_from_combo_text(self, text):
        for row in self.COLUMN_LIST:            
            if self.COLUMN_LIST[row]['name'] == text:
                return self.COLUMN_LIST[row]['label']
        else:
            return 0
                
    def save_fields_to_file(self):        
        field = {}
        field[0] = {'index': self.get_index_of_selected_in_combo_from_combo_text(self.tagComboBox_0.currentText()), 'column':self.tagComboBox_0.currentText() ,'prompt': self.tagPlainText_0.toPlainText()}
        field[1] = {'index': self.get_index_of_selected_in_combo_from_combo_text(self.tagComboBox_1.currentText()), 'column':self.tagComboBox_1.currentText() ,'prompt': self.tagPlainText_1.toPlainText()}
        field[2] = {'index': self.get_index_of_selected_in_combo_from_combo_text(self.tagComboBox_2.currentText()), 'column':self.tagComboBox_2.currentText() ,'prompt': self.tagPlainText_2.toPlainText()}
        field[3] = {'index': self.get_index_of_selected_in_combo_from_combo_text(self.tagComboBox_3.currentText()), 'column':self.tagComboBox_3.currentText() ,'prompt': self.tagPlainText_3.toPlainText()}
        UIState.saveUIFields(field)
        del field
        
    def load_fields_from_file(self):
        try:
            field_json = UIState.loadUIFields()
            fields = {}
            for k in field_json:
                field_json[k]['index'] = int(field_json[k]['index'])
                fields[int(k)] = field_json[k]
            del field_json           
            if fields[0]['index'] != 0 or fields[0]['prompt'] != "":
                if fields[0]['index'] != 0:                    
                    self.tagComboBox_0.setCurrentIndex( int( self.get_index_of_selected_in_combo_from_combo_text(fields[0]['column']) ) )
                if fields[0]['prompt'] != "":
                    self.tagPlainText_0.setPlainText(fields[0]['prompt'])                    
                
            if fields[1]['index'] != 0 or fields[1]['prompt'] != "":
                if fields[1]['index'] != 0:
                    self.tagComboBox_1.setCurrentIndex( int( self.get_index_of_selected_in_combo_from_combo_text(fields[1]['column']) ) )
                if fields[1]['prompt'] != "":
                    self.tagPlainText_1.setPlainText(fields[1]['prompt'])
                self.horizontalLayoutWidget_1.setVisible(True)
                self.COLUMN_WIDGET_VISIBLE_COUNT += 1
            
                if fields[2]['index'] != 0 or fields[2]['prompt'] != "":
                    if fields[2]['index'] != 0:
                        self.tagComboBox_2.setCurrentIndex( int( self.get_index_of_selected_in_combo_from_combo_text(fields[2]['column']) ) )
                    if fields[2]['prompt'] != "":
                        self.tagPlainText_2.setPlainText(fields[2]['prompt'])
                    self.horizontalLayoutWidget_2.setVisible(True)        
                    self.COLUMN_WIDGET_VISIBLE_COUNT += 1
                    self.tagRemoveButton_1.setEnabled(False)
                    
                    if fields[3]['index'] != 0 or fields[3]['prompt'] != "":
                        if fields[3]['index'] != 0:
                            self.tagComboBox_3.setCurrentIndex( int( self.get_index_of_selected_in_combo_from_combo_text(fields[3]['column']) ) )
                        if fields[3]['prompt'] != "":
                            self.tagPlainText_3.setPlainText(fields[3]['prompt'])
                        self.horizontalLayoutWidget_3.setVisible(True)
                        self.COLUMN_WIDGET_VISIBLE_COUNT += 1
                        self.tagRemoveButton_2.setEnabled(False)
            del fields
            
        except Exception as e:
            print(e)
        
    def closeEvent(self, event):
        self.save_fields_to_file()
        self.stop_extracting()
        self.stop_ticker_thread()
        print("Stopping Threads.. Saving then window Closing..")
    
    def empty_fields_check(self):
        ## check if the fields are empty
        if self.tagComboBox_0.currentIndex() == 0 or self.tagPlainText_0.toPlainText() == "":
            return True
        if self.horizontalLayoutWidget_1.isVisible():
            if self.tagComboBox_1.currentIndex() == 0 or self.tagPlainText_1.toPlainText() == "":
                return True
        if self.horizontalLayoutWidget_2.isVisible():
            if self.tagComboBox_2.currentIndex() == 0 or self.tagPlainText_2.toPlainText() == "":
                return True
        if self.horizontalLayoutWidget_3.isVisible():
            if self.tagComboBox_3.currentIndex() == 0 or self.tagPlainText_3.toPlainText() == "":
                return True       
        return False
    
    def workout_percentage(self, total_count):
        self.PROGRESS_SINGLE_PERCENT = 1 / total_count * 100
    
    @QtCore.pyqtSlot(int)
    def update_progress_bar(self, value):
        self.mainProgressBar.setValue(value)
        
    def calc_progress_bar(self, current_count):
        self.PROGRESS_CURRENT_PERCENT = int(round(current_count * self.PROGRESS_SINGLE_PERCENT))    
        self.update_progress_bar(self.PROGRESS_CURRENT_PERCENT)
        if self.PROGRESS_CURRENT_PERCENT == 100:
            self.mainProgressBar.setStyleSheet("QProgressBar{ border: 1px solid grey; border-radius: 5px; text-align: center } QProgressBar::chunk:horizontal { background: qlineargradient(x1: 0, y1: 0.3, x2: 1, y2: 0.3, stop: 0 #5c9301,stop: 0.5 #6aac00,stop: 1 #5c9301);}")
            self.stopButton.setVisible(False)
    
    def get_ebook_file_url(self, title):
        return self.sqldbadapter.get_best_ebook_file(title)
    
    def get_selected_files_in_main_gui(self):
        from calibre.gui2 import error_dialog, info_dialog        
        book_list = {}        
        # Get currently selected books
        rows = self.gui.library_view.selectionModel().selectedRows()
        if not rows or len(rows) == 0:
            return error_dialog(self.gui, 'Can not start Tagging..',
                             'No books selected', show=True)
            
        # Map the rows to book ids
        ids = list(map(self.gui.library_view.model().id, rows))
        db = self.db.new_api
        
        ## compile a list of books
        tmp_id=1
        for book_id in ids:
            #print("Book:" + str(book_id))
            # Get the current metadata for this book from the db
            mi = db.get_metadata(book_id, get_cover=False, cover_as_data=False)
            book_file = self.get_ebook_file_url( str(mi.title) )
            #print(mi)
            if book_file != "":
                book_list[tmp_id] = {'bid': book_id,'title': mi.title,'book_file': book_file }
                tmp_id += 1
            else:
                print("No Valid Book File Found!")
        return book_list
    
    def reset_progress_bar(self):
        self.mainProgressBar.setValue(0)
        self.mainProgressBar.setStyleSheet("QProgressBar{ border: 1px solid grey; border-radius: 5px; text-align: center } QProgressBar::chunk:horizontal { background: qlineargradient(x1: 0, y1: 0.3, x2: 1, y2: 0.3, stop: 0 #037ab6,stop: 0.5 #019ccb,stop: 1 #037ab6);}")
        self.mainProgressBar.resetFormat()
    
    def duplicate_columns_check(self):
        columns_selected = []
        columns_selected.append(self.tagComboBox_0.currentText())
        columns_selected.append(self.tagComboBox_1.currentText())
        columns_selected.append(self.tagComboBox_2.currentText())
        columns_selected.append(self.tagComboBox_3.currentText())
        columns_selected = list(filter(None, columns_selected))
        return any(columns_selected.count(itm) > 1 for itm in columns_selected)

    def have_empty_fields_warning(self):
        message_box = QMessageBox()
        message_box.critical(self, 'Empty Fields!', f'You Have not completed all the fields. Some fields are empty.\nPlease go back and complete each field before we can continue!!')
        print(message_box.result())
    
    def duplicate_columns_warning(self):
        message_box = QMessageBox()
        message_box.critical(self, 'Duplicate Columns!', f'You currently have duplicate columns selected.\nPlease go back and ensure each column is unique before we can continue!!')
        print(message_box.result())
    
    def validate_form(self):
        if self.empty_fields_check():
            self.have_empty_fields_warning()
            return False
        elif self.duplicate_columns_check():
            self.duplicate_columns_warning()
            return False
        else:
            return True
    
    def stop_extraction_thread(self):
        if self.EXTRACTION_THREAD is not None and self.EXTRACTION_THREAD.is_alive():
            self.EXTRACTION_THREAD.abort_thread()
            self.TICKER_THREAD.abort_thread()
        self.stop_ticker_thread()
        self.progressStatusLabel.setText("")
        self.progressSubStatusLabel.setText("")
        self.reviewButton.setVisible(False)
    
    def stop_ticker_thread(self):
        if self.TICKER_THREAD is not None and self.TICKER_THREAD.is_alive():
            self.TICKER_THREAD.abort_thread()
            while self.TICKER_THREAD.is_alive():
                try:
                    self.TICKER_THREAD.join()
                except:
                    print("Couldn't join ticker thread!")
            self.TICKER_THREAD = None
            print("Ticker Stopped!")
        
    def start_ticker_thread(self):
        if self.TICKER_THREAD == None:
            # instanciate the ticker thread
            self.TICKER_THREAD = ticker.JobProgressTicker(self)
            if self.TICKER_THREAD.started != True:                
                self.TICKER_THREAD.start()
                self.TICKER_THREAD.started = True
                print("Ticker Started!")
    
    def start_extracting(self, book_list):
        self.start_ticker_thread()
        self.EXTRACTION_THREAD = JobThread(self, book_list)
        self.EXTRACTION_THREAD.start()
        self.THREAD_PROGRESS = 0
        self.mainProgressBar.valueChanged.connect(self.update_progress_bar)
        self.progressSubStatusLabel.setText("")
        return
        
    def started_extract_so_enable_buttons(self):
        self.mainProgressBar.setVisible(True)
        self.reset_progress_bar()
        self.stopButton.setVisible(True)
        self.extractTagsBtn.setEnabled(False)
        
    def stopped_extract_so_disable_buttons(self):
        self.stopButton.setVisible(False)
        self.reviewButton.setVisible(False)
        self.stop_extraction_thread()
        self.progressStatusLabel.setText("")
        self.progressSubStatusLabel.setText("")
        self.extractTagsBtn.setEnabled(True)
        self.progressSubStatusLabel.setText("")
    
    def stopped_extract_due_to_error(self):
        self.mainProgressBar.setStyleSheet("QProgressBar{ border: 1px solid grey; border-radius: 5px; text-align: center } QProgressBar::chunk:horizontal { background: qlineargradient(x1: 0, y1: 0.3, x2: 1, y2: 0.3, stop: 0 #d80000,stop: 0.5 #ff0000,stop: 1 #d80000);}")
        self.mainProgressBar.setValue(100)
        self.mainProgressBar.setFormat("ERROR")
        self.stopButton.setVisible(False)
        self.reviewButton.setVisible(False)
        self.stop_extraction_thread()
        self.extractTagsBtn.setEnabled(True)
    
    def extract_complete(self):
        self.stop_ticker_thread()
        self.progressStatusLabel.setText("")
        self.progressSubStatusLabel.setText("")
        self.extractTagsBtn.setEnabled(True)
        if len(self.AI_ANSWERS) > 0:
            self.reviewButton.setVisible(True)
    
    def stop_extracting(self):
        self.mainProgressBar.setStyleSheet("QProgressBar{ border: 1px solid grey; border-radius: 5px; text-align: center } QProgressBar::chunk:horizontal { background: qlineargradient(x1: 0, y1: 0.3, x2: 1, y2: 0.3, stop: 0 #d80000,stop: 0.5 #ff0000,stop: 1 #d80000);}")
        self.mainProgressBar.setValue(100)
        self.mainProgressBar.setFormat("Stopped")
        self.stopped_extract_so_disable_buttons()
    
    def get_prompts_for_submission(self):
        prompts = {}
        prompts[0] = {"label": self.get_label_of_selected_in_combo_from_combo_text(self.tagComboBox_0.currentText()), "prompt": self.tagPlainText_0.toPlainText()}
        if self.horizontalLayoutWidget_1.isVisible():
            prompts[1] = {"label": self.get_label_of_selected_in_combo_from_combo_text(self.tagComboBox_1.currentText()), "prompt": self.tagPlainText_1.toPlainText()}
            if self.horizontalLayoutWidget_2.isVisible():
                prompts[2] = {"label": self.get_label_of_selected_in_combo_from_combo_text(self.tagComboBox_2.currentText()), "prompt": self.tagPlainText_2.toPlainText()}
                if self.horizontalLayoutWidget_3.isVisible():
                    prompts[3] = {"label": self.get_label_of_selected_in_combo_from_combo_text(self.tagComboBox_3.currentText()), "prompt": self.tagPlainText_3.toPlainText()}
        return prompts
    
    def extract_tags(self):        
        if self.validate_form():
            self.started_extract_so_enable_buttons()
            book_list = self.get_selected_files_in_main_gui()
            self.start_extracting(book_list)
        
    def filter_remaining_columns(self, dct, remove_list):
        remaining_columns = {}
        tmp_id = 1
        for row in dct:
            if dct[row]['name'] in remove_list:
                continue
            else:
                remaining_columns[tmp_id] = {'index':dct[row]['index'], 'name': dct[row]['name']}
                tmp_id += 1
        return remaining_columns
    
    def get_currently_selected_combo_choices(self):
        ## get current combo choices
        cb = {}
        cb[0] = {'index': self.tagComboBox_0.currentIndex(), 'name': str(self.tagComboBox_0.currentText())}
        cb[1] = {'index': self.tagComboBox_1.currentIndex(), 'name': str(self.tagComboBox_1.currentText())}
        cb[2] = {'index': self.tagComboBox_2.currentIndex(), 'name': str(self.tagComboBox_2.currentText())}
        cb[3] = {'index': self.tagComboBox_3.currentIndex(), 'name': str(self.tagComboBox_3.currentText())}
        
        self.tagComboBox_0.clear()
        self.tagComboBox_1.clear()
        self.tagComboBox_2.clear()
        self.tagComboBox_3.clear()

        if cb[0]['index'] != 0:
            self.tagComboBox_0.insertItem(-1,"")
        if cb[1]['index'] != 0:
            self.tagComboBox_1.insertItem(-1,"")
        if cb[2]['index'] != 0:
            self.tagComboBox_2.insertItem(-1,"")
        if cb[3]['index'] != 0:
            self.tagComboBox_3.insertItem(-1,"")
        
        self.tagComboBox_0.setCurrentIndex(-1)
        self.tagComboBox_1.setCurrentIndex(-1)
        self.tagComboBox_2.setCurrentIndex(-1)
        self.tagComboBox_3.setCurrentIndex(-1)
        
        selected_columns = []
        for cid in cb:
            if cb[cid]['name'] != '':
                selected_columns.append(cb[cid]['name'])
        
        return cb, selected_columns
    
    def update_combo_choices(self):
        
        cb, selected = self.get_currently_selected_combo_choices()
        
        try:
            ## get the remaining columns and add them to the list                
            remaining_columns = self.filter_remaining_columns(self.COLUMN_LIST, selected)
            if len(remaining_columns) > 0:
                for colid in remaining_columns:
                    self.tagComboBox_0.insertItem(remaining_columns[colid]['index'], remaining_columns[colid]['name'])
                    self.tagComboBox_1.insertItem(remaining_columns[colid]['index'], remaining_columns[colid]['name'])
                    self.tagComboBox_2.insertItem(remaining_columns[colid]['index'], remaining_columns[colid]['name'])
                    self.tagComboBox_3.insertItem(remaining_columns[colid]['index'], remaining_columns[colid]['name'])
                
        except Exception as e:
            print(f"Couldnt Write Columns {e}")
        
        try:
            ## add the selected item back into the combo box
            if cb[0]['index'] != -1:
                self.tagComboBox_0.insertItem(cb[0]['index'], cb[0]['name'])
                self.tagComboBox_0.setCurrentIndex(cb[0]['index'])
            if cb[1]['index'] != -1:
                self.tagComboBox_1.insertItem(cb[1]['index'], cb[1]['name'])
                self.tagComboBox_1.setCurrentIndex(cb[1]['index'])
            if cb[2]['index'] != -1:
                self.tagComboBox_2.insertItem(cb[2]['index'], cb[2]['name'])
                self.tagComboBox_2.setCurrentIndex(cb[2]['index'])
            if cb[3]['index'] != -1:
                self.tagComboBox_3.insertItem(cb[3]['index'], cb[3]['name'])
                self.tagComboBox_3.setCurrentIndex(cb[3]['index'])           
            
        except Exception as e:
            print(f"Couldnt Update Current Index {e}")
        
        
    def refresh_combo_choices(self, index):
        self.update_combo_choices()
                
    def get_custom_columns(self):
        VALID_DATATYPES =  ['text', 'comments', 'int', 'float', 'datetime', 'bool']
        db = self.db.new_api
        column_field_list = {}
        temp_column_list = self.db.custom_field_keys(include_composites=False)
        temp_column_list.sort()
        self.custom_columns_dict = self.gui.current_db.field_metadata.custom_field_metadata()
        tmp_id = 1
        #print(self.custom_columns_dict)
        for row in temp_column_list:
            datatype = self.custom_columns_dict[row]['datatype']
            if datatype not in VALID_DATATYPES:
                continue
            column_id = self.custom_columns_dict[row]['colnum']
            column_name = self.custom_columns_dict[row]['name']
            column_label = self.custom_columns_dict[row]['label']
            column_table = self.custom_columns_dict[row]['table']
            column_desc = self.custom_columns_dict[row]['display']['description']
            current_column = {"index": tmp_id, "id": column_id, "name": column_name, "label": column_label, "dbtable": column_table, "col_desc": column_desc, "data_type": datatype}
            column_field_list[tmp_id] = current_column
            tmp_id += 1
        #END FOR
        self.COLUMN_LIST_COUNT = len(column_field_list)
        self.COLUMN_LIST = column_field_list
        del self.custom_columns_dict
        del tmp_id
        return column_field_list
    
    def columns_for_combo(self):
        if self.COLUMN_LIST == None or len(self.COLUMN_LIST) == 0:
            return self.get_custom_columns()
        else:
            return self.COLUMN_LIST
    
    def add_columns_to_combo(self, combobox):
        columns = self.columns_for_combo()
        # add blank column
        combobox.insertItem(-1, "")
        for colid in columns:
            combobox.insertItem(columns[colid]['index'], columns[colid]['name'])
    
    def not_enough_columns_alert(self):
        message_box = QMessageBox()
        message_box.critical(self, 'Not Enough Columns!', f'You currently only have {self.COLUMN_LIST_COUNT} custom columns, you can add more under `Preferences`>`Add Your Own Columns`')
        print(message_box.result())
    
    def add_column_entry_form(self):
        currently_visible = self.COLUMN_WIDGET_VISIBLE_COUNT
        column_list_count = self.COLUMN_LIST_COUNT-1
        if currently_visible == column_list_count:
            self.not_enough_columns_alert()
            return
            
        if currently_visible >= 0 and currently_visible <= 2:
            if currently_visible == 0:
                self.horizontalLayoutWidget_1.setVisible(True)
                currently_visible += 1
            elif currently_visible == 1:
                self.horizontalLayoutWidget_2.setVisible(True)
                currently_visible += 1
                self.tagRemoveButton_1.setEnabled(False)
            elif currently_visible == 2:
                self.horizontalLayoutWidget_3.setVisible(True)
                currently_visible += 1
                self.tagRemoveButton_2.setEnabled(False)
                self.addTagBtn.setEnabled(False)
            if currently_visible != self.COLUMN_WIDGET_VISIBLE_COUNT:
                self.COLUMN_WIDGET_VISIBLE_COUNT = currently_visible
    
    def check_removed_column_empty(self, prompt_box):
        if prompt_box.toPlainText() != "" and prompt_box.toPlainText() != None:
            message_box = QMessageBox()
            #message_box.icon(self.icon)
            message_box.critical(self, 'Delete AI Prompt?', 'This row has information typed into the prompt, are you sure you want to remove this row? this can not be undone?')
            print(message_box.result())
    
    def remove_column_entry_form(self):
        currently_visible = self.COLUMN_WIDGET_VISIBLE_COUNT
        if currently_visible >= 1 and currently_visible <= 3:
            if currently_visible == 1:
                self.check_removed_column_empty(self.tagPlainText_1)
                self.horizontalLayoutWidget_1.setVisible(False)
                self.tagComboBox_1.setCurrentIndex(-1)
                #self.update_combo_choices()
                currently_visible=currently_visible-1
            elif currently_visible == 2:
                self.check_removed_column_empty(self.tagPlainText_2)
                self.horizontalLayoutWidget_2.setVisible(False)
                self.tagComboBox_2.setCurrentIndex(-1)
                #self.update_combo_choices()
                currently_visible=currently_visible-1
                self.tagRemoveButton_1.setEnabled(True)
            elif currently_visible == 3:
                self.check_removed_column_empty(self.tagPlainText_3)
                self.horizontalLayoutWidget_3.setVisible(False)
                self.tagComboBox_3.setCurrentIndex(-1)
                #self.update_combo_choices()
                currently_visible=currently_visible-1
                self.tagRemoveButton_2.setEnabled(True)
                self.addTagBtn.setEnabled(True)
            if currently_visible != self.COLUMN_WIDGET_VISIBLE_COUNT:
                self.COLUMN_WIDGET_VISIBLE_COUNT = currently_visible
    
    def gui_debug(self):
        import json
        self.AI_ANSWERS[1] = json.loads('{"bid": 2, "title": "1000 Best Tips for ADHD: Expert Answers and Bright Advice to Help You and Your Child", "answers": {"filestructure": "/Health/Mental Health/ADHD/", "dragons": "No", "wizards": "No", "maincharacter": "Not Available"}}')
        self.open_review_dialog()
    
    def extract_complete_open_dialog(self):
        if self.reviewDialogCheckbox.isChecked():
            self.reviewDialogCheckbox.setChecked(False)
            self.open_review_dialog()
    
    def open_review_dialog(self):
        review_payload = {
                            'vc_count': self.COLUMN_WIDGET_VISIBLE_COUNT,
                            'combo_0_selected': self.tagComboBox_0.currentText(),
                            'combo_0_label': self.get_label_of_selected_in_combo_from_combo_text(self.tagComboBox_0.currentText()),
                            'combo_1_selected': self.tagComboBox_1.currentText(),
                            'combo_1_label': self.get_label_of_selected_in_combo_from_combo_text(self.tagComboBox_1.currentText()),
                            'combo_2_selected': self.tagComboBox_2.currentText(),
                            'combo_2_label': self.get_label_of_selected_in_combo_from_combo_text(self.tagComboBox_2.currentText()),
                            'combo_3_selected': self.tagComboBox_3.currentText(),
                            'combo_3_label': self.get_label_of_selected_in_combo_from_combo_text(self.tagComboBox_3.currentText()),
                        }
        return self.show_review_dialog(self, review_payload, self.AI_ANSWERS)

    
    ### PART OF THE DEMO PLUGIN ###
    '''
    def marked(self):
        ### Show books with only one format ###
        db = self.db.new_api
        matched_ids = {book_id for book_id in db.all_book_ids() if len(db.formats(book_id)) == 1}
        # Mark the records with the matching ids
        # new_api does not know anything about marked books, so we use the full
        # db object
        self.db.set_marked_ids(matched_ids)

        # Tell the GUI to search for all marked records
        self.gui.search.setEditText('marked:true')
        self.gui.search.do_search()
    '''
    
    def config(self):
        self.do_user_config(parent=self)
        
    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "AI Tag Extractor"))
        
        self.pluginTitleLabel.setWhatsThis(_translate("self", "A Plugin for Extracting Tags from Books using the power of Artificial Intelligence"))
        self.pluginTitleLabel.setText(_translate("self", "AI Tag Extractor"))
        
        self.addTagBtn.setText(_translate("Dialog", "Add Tag"))
        self.columnLabel.setText(_translate("Dialog", "<html><head/><body><p><span style=\" font-weight:600;\">Column:</span></p></body></html>"))
        self.aiPromptLabel.setText(_translate("Dialog", "<html><head/><body><p><span style=\" font-weight:600;\">A.I Prompt:</span></p></body></html>"))
        
        self.tagComboBox_0.setToolTip(_translate("Dialog", "Choose a custom column for the answer from the A.I to be saved into."))
        self.tagPlainText_0.setPlaceholderText(_translate("Dialog", "Type Prompt to send to the A.I..."))
        
        self.tagComboBox_1.setToolTip(_translate("Dialog", "Choose a custom column for the answer from the A.I to be saved into."))
        self.tagPlainText_1.setPlaceholderText(_translate("Dialog", "Type Prompt to send to the A.I..."))
        self.tagRemoveButton_1.setToolTip(_translate("Dialog", "Remove Custom Prompt Column"))
        
        self.tagComboBox_2.setToolTip(_translate("Dialog", "Choose a custom column for the answer from the A.I to be saved into."))
        self.tagPlainText_2.setPlaceholderText(_translate("Dialog", "Type Prompt to send to the A.I..."))
        self.tagRemoveButton_2.setToolTip(_translate("Dialog", "Remove Custom Prompt Column"))
        
        self.tagComboBox_3.setToolTip(_translate("Dialog", "Choose a custom column for the answer from the A.I to be saved into."))
        self.tagPlainText_3.setPlaceholderText(_translate("Dialog", "Type Prompt to send to the A.I..."))
        self.tagRemoveButton_3.setToolTip(_translate("Dialog", "Remove Custom Prompt Column"))
        
        self.stopButton.setToolTip(_translate("Dialog", "Stop the Process"))
        self.reviewButton.setToolTip(_translate("Dialog", "Review Extracted Tags"))
        self.extractTagsBtn.setText(_translate("Dialog", " Extract Tags"))
        
        self.designedByLabel.setText(_translate("Dialog", "<html><head/><body><p>Developed by Digital Assassins</p></body></html>"))
        self.poweredByLabel.setText(_translate("Dialog", "Powered By <a href=\"https://anythingllm.com/\">AnythingLLM</a>, <a href=\"https://www.nomic.ai/gpt4all/\">GPT4ALL</a>, <a href=\"https://openwebui.com/\">OpenWebUI</a>"))
