import typing

from qtpy import QtWidgets as QW

from hydrus.core import HydrusConstants as HC
from hydrus.core import HydrusExceptions
from hydrus.core import HydrusGlobals as HG

from hydrus.client import ClientApplicationCommand as CAC
from hydrus.client import ClientConstants as CC
from hydrus.client import ClientGlobals as CG
from hydrus.client.gui import ClientGUIDialogsMessage
from hydrus.client.gui import ClientGUIScrolledPanels
from hydrus.client.gui import ClientGUIShortcuts
from hydrus.client.gui import QtPorting as QP
from hydrus.client.gui.search import ClientGUIACDropdown
from hydrus.client.gui.widgets import ClientGUICommon
from hydrus.client.media import ClientMediaFileFilter

class LocalFilesSubPanel( QW.QWidget ):
    
    def __init__( self, parent: QW.QWidget ):
        
        QW.QWidget.__init__( self, parent )
        
        self._add_or_move_action = ClientGUICommon.BetterChoice( self )
        
        self._add_or_move_action.addItem( 'add to', HC.CONTENT_UPDATE_ADD )
        self._add_or_move_action.addItem( 'move to', HC.CONTENT_UPDATE_MOVE )
        
        self._add_or_move_action.SetValue( HC.CONTENT_UPDATE_ADD )
        
        self._service_keys = ClientGUICommon.BetterChoice( self )
        
        #
        
        services = CG.client_controller.services_manager.GetServices( ( HC.LOCAL_FILE_DOMAIN, ) )
        
        for service in services:
            
            service_name = service.GetName()
            service_key = service.GetServiceKey()
            
            self._service_keys.addItem( service_name, service_key )
            
        
        #
        
        vbox = QP.VBoxLayout()
        
        ratings_numerical_hbox = QP.HBoxLayout()
        
        QP.AddToLayout( vbox, self._add_or_move_action, CC.FLAGS_EXPAND_PERPENDICULAR )
        QP.AddToLayout( vbox, self._service_keys, CC.FLAGS_EXPAND_PERPENDICULAR )
        
        self.setLayout( vbox )
        
    
    def GetValue( self ):
        
        service_key = self._service_keys.GetValue()
        
        if service_key is None:
            
            raise HydrusExceptions.VetoException( 'Please select a service!' )
            
        
        action = self._add_or_move_action.GetValue()
        
        value = None
        
        return CAC.ApplicationCommand( CAC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_FILES, action, value ) )
        
    
    def SetValue( self, action: int, service_key: bytes ):
        
        self._add_or_move_action.SetValue( action )
        
        self._service_keys.SetValue( service_key )
        
    
class RatingLikeSubPanel( QW.QWidget ):
    
    def __init__( self, parent: QW.QWidget ):
        
        QW.QWidget.__init__( self, parent )
        
        self._flip_or_set_action = ClientGUICommon.BetterChoice( self )
        
        self._flip_or_set_action.addItem( 'set', HC.CONTENT_UPDATE_SET )
        self._flip_or_set_action.addItem( 'flip on and off', HC.CONTENT_UPDATE_FLIP )
        
        self._flip_or_set_action.SetValue( HC.CONTENT_UPDATE_SET )
        
        self._service_keys = ClientGUICommon.BetterChoice( self )
        self._ratings_like_like = QW.QRadioButton( 'like', self )
        self._ratings_like_dislike = QW.QRadioButton( 'dislike', self )
        self._ratings_like_remove = QW.QRadioButton( 'remove rating', self )
        
        #
        
        services = CG.client_controller.services_manager.GetServices( ( HC.LOCAL_RATING_LIKE, ) )
        
        if len( services ) == 0:
            
            self._service_keys.addItem( 'you have no like/dislike rating services', None )
            
        else:
            
            for service in services:
                
                service_name = service.GetName()
                service_key = service.GetServiceKey()
                
                self._service_keys.addItem( service_name, service_key )
                
            
        
        self._ratings_like_like.setChecked( True )
        
        #
        
        vbox = QP.VBoxLayout()
        
        ratings_like_hbox = QP.HBoxLayout()
        
        QP.AddToLayout( ratings_like_hbox, self._service_keys, CC.FLAGS_EXPAND_BOTH_WAYS )
        QP.AddToLayout( ratings_like_hbox, self._ratings_like_like, CC.FLAGS_CENTER_PERPENDICULAR )
        QP.AddToLayout( ratings_like_hbox, self._ratings_like_dislike, CC.FLAGS_CENTER_PERPENDICULAR )
        QP.AddToLayout( ratings_like_hbox, self._ratings_like_remove, CC.FLAGS_CENTER_PERPENDICULAR )
        
        QP.AddToLayout( vbox, self._flip_or_set_action, CC.FLAGS_EXPAND_PERPENDICULAR )
        QP.AddToLayout( vbox, ratings_like_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
        
        self.setLayout( vbox )
        
        self._ratings_like_remove.toggled.connect( self._UpdateFlipAllowed )
        
    
    def _UpdateFlipAllowed( self ):
        
        if self._ratings_like_remove.isChecked():
            
            self._flip_or_set_action.SetValue( HC.CONTENT_UPDATE_SET )
            self._flip_or_set_action.setEnabled( False )
            
        else:
            
            self._flip_or_set_action.setEnabled( True )
            
        
    
    def GetValue( self ):
        
        service_key = self._service_keys.GetValue()
        
        if service_key is None:
            
            raise HydrusExceptions.VetoException( 'Please select a rating service!' )
            
        
        action = self._flip_or_set_action.GetValue()
        
        if self._ratings_like_like.isChecked():
            
            value = 1.0
            
        elif self._ratings_like_dislike.isChecked():
            
            value = 0.0
            
        else:
            
            value = None
            
        
        return CAC.ApplicationCommand( CAC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_RATINGS, action, value ) )
        
    
    def SetValue( self, action: int, service_key: bytes, rating: typing.Optional[ float ] ):
        
        self._flip_or_set_action.SetValue( action )
        
        self._service_keys.SetValue( service_key )
        
        self._ratings_like_remove.setChecked( rating is None )
        self._ratings_like_like.setChecked( rating == 1.0 )
        self._ratings_like_dislike.setChecked( rating == 0.0 )
        
    
class RatingNumericalSubPanel( QW.QWidget ):
    
    def __init__( self, parent: QW.QWidget ):
        
        QW.QWidget.__init__( self, parent )
        
        self._current_ratings_numerical_service = None
        
        self._flip_or_set_action = ClientGUICommon.BetterChoice( self )
        
        self._flip_or_set_action.addItem( 'set', HC.CONTENT_UPDATE_SET )
        self._flip_or_set_action.addItem( 'flip on and off', HC.CONTENT_UPDATE_FLIP )
        
        self._flip_or_set_action.SetValue( HC.CONTENT_UPDATE_SET )
        
        self._service_keys = ClientGUICommon.BetterChoice( self )
        self._service_keys.currentIndexChanged.connect( self._UpdateSliderRange )
        self._ratings_numerical_slider = QP.LabelledSlider( self )
        self._ratings_numerical_remove = QW.QCheckBox( 'remove rating', self )
        
        #
        
        services = CG.client_controller.services_manager.GetServices( ( HC.LOCAL_RATING_NUMERICAL, ) )
        
        if len( services ) == 0:
            
            self._service_keys.addItem( 'you have no numerical rating services', None )
            
        else:
            
            for service in services:
                
                service_name = service.GetName()
                service_key = service.GetServiceKey()
                
                self._service_keys.addItem( service_name, service_key )
                
            
        
        self._UpdateSliderRange()
        
        #
        
        vbox = QP.VBoxLayout()
        
        ratings_numerical_hbox = QP.HBoxLayout()
        
        QP.AddToLayout( ratings_numerical_hbox, self._service_keys, CC.FLAGS_CENTER_PERPENDICULAR_EXPAND_DEPTH )
        QP.AddToLayout( ratings_numerical_hbox, self._ratings_numerical_slider, CC.FLAGS_CENTER_PERPENDICULAR )
        QP.AddToLayout( ratings_numerical_hbox, self._ratings_numerical_remove, CC.FLAGS_CENTER_PERPENDICULAR )
        
        QP.AddToLayout( vbox, self._flip_or_set_action, CC.FLAGS_EXPAND_PERPENDICULAR )
        QP.AddToLayout( vbox, ratings_numerical_hbox, CC.FLAGS_EXPAND_PERPENDICULAR )
        
        self.setLayout( vbox )
        
        self._ratings_numerical_remove.toggled.connect( self._UpdateFlipAllowed )
        
    
    def _UpdateFlipAllowed( self ):
        
        remove_on = self._ratings_numerical_remove.isChecked()
        
        if remove_on:
            
            self._flip_or_set_action.SetValue( HC.CONTENT_UPDATE_SET )
            
        
        self._flip_or_set_action.setEnabled( not remove_on )
        self._ratings_numerical_slider.setEnabled( not remove_on )
        
    
    def _UpdateSliderRange( self ):
        
        service_key = self._service_keys.GetValue()
        
        if service_key is not None:
            
            service = CG.client_controller.services_manager.GetService( service_key )
            
            self._current_ratings_numerical_service = service
            
            num_stars = service.GetNumStars()
            
            allow_zero = service.AllowZero()
            
            if allow_zero:
                
                minimum = 0
                
            else:
                
                minimum = 1
                
            
            self._ratings_numerical_slider.SetRange( minimum, num_stars )
            
        
    
    def GetValue( self ):
        
        service_key = self._service_keys.GetValue()
        
        if service_key is None:
            
            raise HydrusExceptions.VetoException( 'Please select a rating service!' )
            
        
        action = self._flip_or_set_action.GetValue()
        
        if self._ratings_numerical_remove.isChecked():
            
            rating = None
            
        else:
            
            value = self._ratings_numerical_slider.GetValue()
            
            rating = self._current_ratings_numerical_service.ConvertStarsToRating( value )
            
        
        return CAC.ApplicationCommand( CAC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_RATINGS, action, rating ) )
        
    
    def SetValue( self, action: int, service_key: bytes, rating: typing.Optional[ float ] ):
        
        self._flip_or_set_action.SetValue( action )
        
        self._service_keys.SetValue( service_key )
        
        self._UpdateSliderRange()
        
        if rating is None:
            
            self._ratings_numerical_remove.setChecked( True )
            
        else:
            
            slider_value = self._current_ratings_numerical_service.ConvertRatingToStars( rating )
            
            self._ratings_numerical_slider.SetValue( slider_value )
            
        
    

class RatingIncDecSubPanel( QW.QWidget ):
    
    def __init__( self, parent: QW.QWidget ):
        
        QW.QWidget.__init__( self, parent )
        
        self._service_keys = ClientGUICommon.BetterChoice( self )
        
        self._ratings_incdec = ClientGUICommon.BetterChoice( self )
        
        self._ratings_incdec.addItem( HC.content_update_string_lookup[ HC.CONTENT_UPDATE_INCREMENT ], HC.CONTENT_UPDATE_INCREMENT )
        self._ratings_incdec.addItem( HC.content_update_string_lookup[ HC.CONTENT_UPDATE_DECREMENT ], HC.CONTENT_UPDATE_DECREMENT )
        
        #
        
        services = CG.client_controller.services_manager.GetServices( ( HC.LOCAL_RATING_NUMERICAL, HC.LOCAL_RATING_INCDEC ) )
        
        if len( services ) == 0:
            
            self._service_keys.addItem( 'you have no numerical or inc/dec rating services', None )
            
        else:
            
            for service in services:
                
                service_name = service.GetName()
                service_key = service.GetServiceKey()
                
                self._service_keys.addItem( service_name, service_key )
                
            
        
        #
        
        hbox = QP.HBoxLayout()
        
        QP.AddToLayout( hbox, self._service_keys, CC.FLAGS_CENTER_PERPENDICULAR_EXPAND_DEPTH )
        QP.AddToLayout( hbox, self._ratings_incdec, CC.FLAGS_CENTER_PERPENDICULAR )
        
        self.setLayout( hbox )
        
    
    def GetValue( self ):
        
        service_key = self._service_keys.GetValue()
        
        if service_key is None:
            
            raise HydrusExceptions.VetoException( 'Please select a rating service!' )
            
        
        action = self._ratings_incdec.GetValue()
        
        distance = 1
        
        return CAC.ApplicationCommand( CAC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_RATINGS, action, distance ) )
        
    
    def SetValue( self, action: int, service_key: bytes, distance: int ):
        
        self._service_keys.SetValue( service_key )
        
        self._ratings_incdec.SetValue( action )
        
    

class SimpleSubPanel( QW.QWidget ):
    
    def __init__( self, parent: QW.QWidget, shortcuts_name: str ):
        
        QW.QWidget.__init__( self, parent )
        
        if shortcuts_name in ClientGUIShortcuts.SHORTCUTS_RESERVED_NAMES:
            
            simple_types = ClientGUIShortcuts.simple_shortcut_name_to_action_lookup[ shortcuts_name ]
            
        else:
            
            simple_types = ClientGUIShortcuts.simple_shortcut_name_to_action_lookup[ 'custom' ]
            
        
        choices = sorted( [ ( CAC.simple_enum_to_str_lookup[ simple_type ], simple_type ) for simple_type in simple_types ] )
        
        self._simple_actions = ClientGUICommon.BetterChoice( self )
        
        for ( display_string, data ) in choices:
            
            self._simple_actions.addItem( display_string, data )
            
        
        #
        
        self._duplicates_type_panel = QW.QWidget( self )
        
        choices = [ ( HC.duplicate_type_string_lookup[ t ], t ) for t in ( HC.DUPLICATE_MEMBER, HC.DUPLICATE_ALTERNATE, HC.DUPLICATE_FALSE_POSITIVE, HC.DUPLICATE_POTENTIAL ) ]
        
        self._duplicate_type = ClientGUICommon.BetterRadioBox( self._duplicates_type_panel, choices = choices )
        
        #
        
        self._thumbnail_rearrange_panel = QW.QWidget( self )
        
        self._thumbnail_rearrange_type = ClientGUICommon.BetterChoice( self )
        
        for rearrange_type in [
            CAC.MOVE_HOME,
            CAC.MOVE_END,
            CAC.MOVE_LEFT,
            CAC.MOVE_RIGHT,
            CAC.MOVE_TO_FOCUS
        ]:
            
            self._thumbnail_rearrange_type.addItem( CAC.move_enum_to_str_lookup[ rearrange_type ], rearrange_type )
            
        
        #
        
        vbox = QP.VBoxLayout()
        
        QP.AddToLayout( vbox, self._thumbnail_rearrange_type, CC.FLAGS_EXPAND_BOTH_WAYS )
        
        self._thumbnail_rearrange_panel.setLayout( vbox )
        
        #
        
        vbox = QP.VBoxLayout()
        
        QP.AddToLayout( vbox, self._duplicate_type, CC.FLAGS_EXPAND_BOTH_WAYS )
        
        self._duplicates_type_panel.setLayout( vbox )
        
        #
        
        self._seek_panel = QW.QWidget( self )
        
        choices = [
            ( 'back', -1 ),
            ( 'forwards', 1 )
        ]
        
        self._seek_direction = ClientGUICommon.BetterRadioBox( self._seek_panel, choices = choices )
        
        self._seek_duration_s = ClientGUICommon.BetterSpinBox( self._seek_panel, max=3599, width = 60 )
        self._seek_duration_ms = ClientGUICommon.BetterSpinBox( self._seek_panel, max=999, width = 60 )
        
        #
        
        self._seek_duration_s.setValue( 5 )
        self._seek_duration_ms.setValue( 0 )
        
        self._seek_duration_s.value() * 1000 + self._seek_duration_ms.value()
        
        #
        
        hbox = QP.HBoxLayout()
        
        QP.AddToLayout( hbox, self._seek_direction, CC.FLAGS_EXPAND_BOTH_WAYS )
        QP.AddToLayout( hbox, self._seek_duration_s, CC.FLAGS_CENTER )
        QP.AddToLayout( hbox, ClientGUICommon.BetterStaticText( self._seek_panel, label = 's' ), CC.FLAGS_CENTER )
        QP.AddToLayout( hbox, self._seek_duration_ms, CC.FLAGS_CENTER )
        QP.AddToLayout( hbox, ClientGUICommon.BetterStaticText( self._seek_panel, label = 'ms' ), CC.FLAGS_CENTER )
        
        self._seek_panel.setLayout( hbox )
        
        #
        
        self._thumbnail_move_panel = QW.QWidget( self )
        
        choices = [ ( CAC.selection_status_enum_to_str_lookup[ s ], s ) for s in [ CAC.SELECTION_STATUS_NORMAL, CAC.SELECTION_STATUS_SHIFT ] ]
        
        self._selection_status = ClientGUICommon.BetterRadioBox( self._thumbnail_move_panel, choices = choices )
        
        self._selection_status.SetValue( CAC.SELECTION_STATUS_NORMAL )
        
        self._move_direction = ClientGUICommon.BetterChoice( self._thumbnail_move_panel )
        
        for m in [ CAC.MOVE_LEFT, CAC.MOVE_RIGHT, CAC.MOVE_UP, CAC.MOVE_DOWN, CAC.MOVE_HOME, CAC.MOVE_END, CAC.MOVE_PAGE_UP, CAC.MOVE_PAGE_DOWN ]:
            
            self._move_direction.addItem( CAC.move_enum_to_str_lookup[ m ], m )
            
        
        #
        
        hbox = QP.HBoxLayout()
        
        QP.AddToLayout( hbox, self._selection_status, CC.FLAGS_CENTER )
        QP.AddToLayout( hbox, self._move_direction, CC.FLAGS_CENTER )
        
        self._thumbnail_move_panel.setLayout( hbox )
        
        #
        
        self._file_filter_panel = QW.QWidget( self )
        
        self._file_filter = ClientGUICommon.BetterChoice( self._file_filter_panel )
        
        for file_filter in [
            ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_ALL ),
            ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_NONE ),
            ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_INBOX ),
            ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_ARCHIVE ),
            ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_LOCAL ),
            ClientMediaFileFilter.FileFilter( ClientMediaFileFilter.FILE_FILTER_FILE_SERVICE, filter_data = CC.TRASH_SERVICE_KEY )
        ]:
            
            self._file_filter.addItem( file_filter.ToString(), file_filter )
            
        
        #
        
        self._hamming_distance_panel = QW.QWidget( self )
        
        self._hamming_distance = ClientGUICommon.BetterSpinBox( self._hamming_distance_panel, min = 0, max = 64 )
        
        #
        
        hbox = QP.HBoxLayout()
        
        QP.AddToLayout( hbox, self._file_filter, CC.FLAGS_CENTER )
        
        self._file_filter_panel.setLayout( hbox )
        
        #
        
        rows = []
        
        rows.append( ( 'Search distance:', self._hamming_distance ) )
        
        gridbox = ClientGUICommon.WrapInGrid( self._hamming_distance_panel, rows )
        
        self._hamming_distance_panel.setLayout( gridbox )
        
        #
        
        vbox = QP.VBoxLayout()
        
        QP.AddToLayout( vbox, self._simple_actions, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        QP.AddToLayout( vbox, self._duplicates_type_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        QP.AddToLayout( vbox, self._seek_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        QP.AddToLayout( vbox, self._thumbnail_move_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        QP.AddToLayout( vbox, self._file_filter_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        QP.AddToLayout( vbox, self._hamming_distance_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        QP.AddToLayout( vbox, self._thumbnail_rearrange_panel, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        
        self.setLayout( vbox )
        
        self._simple_actions.currentIndexChanged.connect( self._UpdateControls )
        
        self._UpdateControls()
        
    
    def _UpdateControls( self ):
        
        action = self._simple_actions.GetValue()
        
        self._thumbnail_rearrange_panel.setVisible( action == CAC.SIMPLE_REARRANGE_THUMBNAILS )
        self._duplicates_type_panel.setVisible( action == CAC.SIMPLE_SHOW_DUPLICATES )
        self._seek_panel.setVisible( action == CAC.SIMPLE_MEDIA_SEEK_DELTA )
        self._thumbnail_move_panel.setVisible( action == CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS )
        self._file_filter_panel.setVisible( action == CAC.SIMPLE_SELECT_FILES )
        self._hamming_distance_panel.setVisible( action == CAC.SIMPLE_OPEN_SIMILAR_LOOKING_FILES )
        
    
    def GetValue( self ):
        
        action = self._simple_actions.GetValue()
        
        if action == '':
            
            raise HydrusExceptions.VetoException( 'Please select an action!' )
            
        else:
            
            if action == CAC.SIMPLE_SHOW_DUPLICATES:
                
                duplicate_type = self._duplicate_type.GetValue()
                
                simple_data = duplicate_type
                
            elif action == CAC.SIMPLE_MEDIA_SEEK_DELTA:
                
                direction = self._seek_direction.GetValue()
                
                s = self._seek_duration_s.value()
                ms = self._seek_duration_ms.value() + ( 1000 * s )
                
                simple_data = ( direction, ms )
                
            elif action == CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS:
                
                move_direction = self._move_direction.GetValue()
                selection_status = self._selection_status.GetValue()
                
                simple_data = ( move_direction, selection_status )
                
            elif action == CAC.SIMPLE_SELECT_FILES:
                
                file_filter = self._file_filter.GetValue()
                
                simple_data = file_filter
                
            elif action == CAC.SIMPLE_OPEN_SIMILAR_LOOKING_FILES:
                
                hamming_distance = self._hamming_distance.value()
                
                simple_data = hamming_distance
                
            elif action == CAC.SIMPLE_REARRANGE_THUMBNAILS:
                
                rearrange_type = self._thumbnail_rearrange_type.GetValue()
                
                simple_data = ( CAC.REARRANGE_THUMBNAILS_TYPE_COMMAND, rearrange_type )
                
            else:
                
                simple_data = None
                
            
            return CAC.ApplicationCommand.STATICCreateSimpleCommand( action, simple_data = simple_data )
            
        
    
    def SetValue( self, command: CAC.ApplicationCommand ):
        
        action = command.GetSimpleAction()
        
        self._simple_actions.SetValue( action )
        
        if action == CAC.SIMPLE_SHOW_DUPLICATES:
            
            duplicate_type = command.GetSimpleData()
            
            self._duplicate_type.SetValue( duplicate_type )
            
        elif action == CAC.SIMPLE_MEDIA_SEEK_DELTA:
            
            ( direction, ms ) = command.GetSimpleData()
            
            self._seek_direction.SetValue( direction )
            
            s = ms // 1000
            
            ms = ms % 1000
            
            self._seek_duration_s.setValue( s )
            self._seek_duration_ms.setValue( ms )
            
        elif action == CAC.SIMPLE_MOVE_THUMBNAIL_FOCUS:
            
            ( move_direction, selection_status ) = command.GetSimpleData()
            
            self._move_direction.SetValue( move_direction )
            self._selection_status.SetValue( selection_status )
            
        elif action == CAC.SIMPLE_SELECT_FILES:
            
            file_filter = command.GetSimpleData()
            
            self._file_filter.SetValue( file_filter )
            
        elif action == CAC.SIMPLE_OPEN_SIMILAR_LOOKING_FILES:
            
            hamming_distance = command.GetSimpleData()
            
            self._hamming_distance.setValue( hamming_distance )
            
        elif action == CAC.SIMPLE_REARRANGE_THUMBNAILS:
            
            ( rearrange_type, rearrange_data ) = command.GetSimpleData()
            
            self._thumbnail_rearrange_type.SetValue( rearrange_data )
            
        
        self._UpdateControls()
        
    
class TagSubPanel( QW.QWidget ):
    
    def __init__( self, parent: QW.QWidget ):
        
        QW.QWidget.__init__( self, parent )
        
        self._flip_or_set_action = ClientGUICommon.BetterChoice( self )
        
        self._flip_or_set_action.addItem( 'set', HC.CONTENT_UPDATE_SET )
        self._flip_or_set_action.addItem( 'flip on and off', HC.CONTENT_UPDATE_FLIP )
        
        self._flip_or_set_action.SetValue( HC.CONTENT_UPDATE_SET )
        
        self._service_keys = ClientGUICommon.BetterChoice( self )
        
        self._tag_value = QW.QLineEdit( self )
        self._tag_value.setReadOnly( True )
        
        default_location_context = CG.client_controller.new_options.GetDefaultLocalLocationContext()
        
        self._tag_input = ClientGUIACDropdown.AutoCompleteDropdownTagsWrite( self, self.SetTags, default_location_context, CC.COMBINED_TAG_SERVICE_KEY )
        
        #
        
        services = CG.client_controller.services_manager.GetServices( ( HC.LOCAL_TAG, HC.TAG_REPOSITORY ) )
        
        for service in services:
            
            service_name = service.GetName()
            service_key = service.GetServiceKey()
            
            self._service_keys.addItem( service_name, service_key )
            
        
        self._tag_input.SetTagServiceKey( self._service_keys.GetValue() )
        
        #
        
        vbox = QP.VBoxLayout()
        
        tag_sub_vbox = QP.VBoxLayout()
        
        QP.AddToLayout( tag_sub_vbox, self._tag_value, CC.FLAGS_EXPAND_PERPENDICULAR )
        QP.AddToLayout( tag_sub_vbox, self._tag_input, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        
        tag_hbox = QP.HBoxLayout()
        
        QP.AddToLayout( tag_hbox, self._service_keys, CC.FLAGS_CENTER_PERPENDICULAR_EXPAND_DEPTH )
        QP.AddToLayout( tag_hbox, tag_sub_vbox, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        
        QP.AddToLayout( vbox, self._flip_or_set_action, CC.FLAGS_EXPAND_PERPENDICULAR )
        QP.AddToLayout( vbox, tag_hbox, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
        
        self.setLayout( vbox )
        
        #
        
        self._service_keys.currentIndexChanged.connect( self._NewServiceKey )
        
    
    def _NewServiceKey( self ):
        
        self._tag_input.SetTagServiceKey( self._service_keys.GetValue() )
        
    
    def GetValue( self ):
        
        service_key = self._service_keys.GetValue()
        
        if service_key is None:
            
            raise HydrusExceptions.VetoException( 'Please select a tag service!' )
            
        
        action = self._flip_or_set_action.GetValue()
        
        tag = self._tag_value.text()
        
        if tag == '':
            
            raise HydrusExceptions.VetoException( 'Please enter a tag!' )
            
        
        return CAC.ApplicationCommand( CAC.APPLICATION_COMMAND_TYPE_CONTENT, ( service_key, HC.CONTENT_TYPE_MAPPINGS, action, tag ) )
        
    
    def SetTags( self, tags ):
        
        if len( tags ) > 0:
            
            tag = list( tags )[0]
            
            self._tag_value.setText( tag )
            
        
    
    def SetValue( self, action: int, service_key: bytes, tag: str ):
        
        self._flip_or_set_action.SetValue( action )
        
        self._service_keys.SetValue( service_key )
        
        self._tag_value.setText( tag )
        
    

class ApplicationCommandWidget( ClientGUIScrolledPanels.EditPanel ):
    
    PANEL_SIMPLE = 0
    PANEL_TAG = 1
    PANEL_RATING_LIKE = 2
    PANEL_RATING_NUMERICAL = 3
    PANEL_RATING_INCDEC = 4
    PANEL_LOCAL_FILES = 5
    
    def __init__( self, parent: QW.QWidget, command: CAC.ApplicationCommand, shortcuts_name: str ):
        
        ClientGUIScrolledPanels.EditPanel.__init__( self, parent )
        
        #
        
        is_custom_or_media = shortcuts_name not in ClientGUIShortcuts.SHORTCUTS_RESERVED_NAMES or shortcuts_name == 'media'
        
        self._panel_choice = ClientGUICommon.BetterChoice( self )
        
        self._panel_choice.addItem( 'simple command', self.PANEL_SIMPLE )
        
        if is_custom_or_media:
            
            self._panel_choice.addItem( 'tag command', self.PANEL_TAG )
            self._panel_choice.addItem( 'local file command', self.PANEL_LOCAL_FILES )
            self._panel_choice.addItem( 'like/dislike rating command', self.PANEL_RATING_LIKE )
            self._panel_choice.addItem( 'numerical rating command', self.PANEL_RATING_NUMERICAL )
            self._panel_choice.addItem( 'rating increment/decrement command', self.PANEL_RATING_INCDEC )
            
        else:
            
            self._panel_choice.hide()
            
        
        self._simple_sub_panel = SimpleSubPanel( self, shortcuts_name )
        
        self._tag_sub_panel = TagSubPanel( self )
        
        self._rating_like_sub_panel = RatingLikeSubPanel( self )
        
        self._rating_numerical_sub_panel = RatingNumericalSubPanel( self )
        
        self._rating_inc_dec_sub_panel = RatingIncDecSubPanel( self )
        
        self._local_files_sub_panel = LocalFilesSubPanel( self )
        
        #
        
        if command.IsSimpleCommand():
            
            self._simple_sub_panel.SetValue( command )
            
            self._panel_choice.SetValue( self.PANEL_SIMPLE )
            
        elif command.IsContentCommand():
            
            service_key = command.GetContentServiceKey()
            
            if CG.client_controller.services_manager.ServiceExists( service_key ):
                
                service = CG.client_controller.services_manager.GetService( service_key )
                
                action = command.GetContentAction()
                value = command.GetContentValue()
                
            else:
                
                ClientGUIDialogsMessage.ShowWarning( self, 'The service that this command relies upon no longer exists! This command will reset to a default form.' )
                
                local_tag_services = list( CG.client_controller.services_manager.GetServices( ( HC.LOCAL_TAG, ) ) )
                
                service = local_tag_services[0]
                
                service_key = service.GetServiceKey()
                action = HC.CONTENT_UPDATE_SET
                value = 'tag'
                
            
            service_type = service.GetServiceType()
            
            if service_type in HC.REAL_TAG_SERVICES:
                
                tag = value
                
                self._tag_sub_panel.SetValue( action, service_key, tag )
                
                self._panel_choice.SetValue( self.PANEL_TAG )
                
            elif service_type == HC.LOCAL_FILE_DOMAIN:
                
                self._local_files_sub_panel.SetValue( action, service_key )
                
                self._panel_choice.SetValue( self.PANEL_LOCAL_FILES )
                
            elif service_type == HC.LOCAL_RATING_LIKE:
                
                rating = value
                
                self._rating_like_sub_panel.SetValue( action, service_key, rating )
                
                self._panel_choice.SetValue( self.PANEL_RATING_LIKE )
                
            elif service_type == ( HC.LOCAL_RATING_NUMERICAL, HC.LOCAL_RATING_INCDEC ):
                
                if action in ( HC.CONTENT_UPDATE_SET, HC.CONTENT_UPDATE_FLIP ):
                    
                    rating = value
                    
                    self._rating_numerical_sub_panel.SetValue( action, service_key, rating )
                    
                    self._panel_choice.SetValue( self.PANEL_RATING_NUMERICAL )
                    
                elif action in ( HC.CONTENT_UPDATE_INCREMENT, HC.CONTENT_UPDATE_DECREMENT ):
                    
                    distance = 1
                    
                    self._rating_inc_dec_sub_panel.SetValue( action, service_key, distance )
                    
                    self._panel_choice.SetValue( self.PANEL_RATING_INCDEC )
                    
                
            
        
        #
        
        vbox = QP.VBoxLayout()
        
        QP.AddToLayout( vbox, self._panel_choice, CC.FLAGS_EXPAND_PERPENDICULAR )
        QP.AddToLayout( vbox, self._simple_sub_panel, CC.FLAGS_EXPAND_PERPENDICULAR )
        QP.AddToLayout( vbox, self._tag_sub_panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
        QP.AddToLayout( vbox, self._local_files_sub_panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
        QP.AddToLayout( vbox, self._rating_like_sub_panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
        QP.AddToLayout( vbox, self._rating_numerical_sub_panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
        QP.AddToLayout( vbox, self._rating_inc_dec_sub_panel, CC.FLAGS_EXPAND_SIZER_PERPENDICULAR )
        vbox.addStretch( 1 )
        
        self.widget().setLayout( vbox )
        
        self._UpdateVisibleControls()
        
        #
        
        self._panel_choice.currentIndexChanged.connect( self._UpdateVisibleControls )
        
    
    def _UpdateVisibleControls( self ):
        
        panel_type = self._panel_choice.GetValue()
        
        self._simple_sub_panel.setVisible( panel_type == self.PANEL_SIMPLE )
        self._tag_sub_panel.setVisible( panel_type == self.PANEL_TAG )
        self._local_files_sub_panel.setVisible( panel_type == self.PANEL_LOCAL_FILES )
        self._rating_like_sub_panel.setVisible( panel_type == self.PANEL_RATING_LIKE )
        self._rating_numerical_sub_panel.setVisible( panel_type == self.PANEL_RATING_NUMERICAL )
        self._rating_inc_dec_sub_panel.setVisible( panel_type == self.PANEL_RATING_INCDEC )
        
    
    def GetValue( self ):
        
        panel_type = self._panel_choice.GetValue()
        
        if panel_type == self.PANEL_SIMPLE:
            
            return self._simple_sub_panel.GetValue()
            
        elif panel_type == self.PANEL_TAG:
            
            return self._tag_sub_panel.GetValue()
            
        elif panel_type == self.PANEL_LOCAL_FILES:
            
            return self._local_files_sub_panel.GetValue()
            
        elif panel_type == self.PANEL_RATING_LIKE:
            
            return self._rating_like_sub_panel.GetValue()
            
        elif panel_type == self.PANEL_RATING_NUMERICAL:
            
            return self._rating_numerical_sub_panel.GetValue()
            
        elif panel_type == self.PANEL_RATING_INCDEC:
            
            return self._rating_inc_dec_sub_panel.GetValue()
            
        
    
