from qtpy import QtCore as QC
from qtpy import QtWidgets as QW
from qtpy import QtGui as QG

from hydrus.core import HydrusGlobals as HG

from hydrus.client import ClientConstants as CC
from hydrus.client.gui import ClientGUIFunctions
from hydrus.client.gui import QtPorting as QP
from hydrus.client.gui.widgets import ClientGUICommon

AUDIO_GLOBAL = 0
AUDIO_MEDIA_VIEWER = 1
AUDIO_PREVIEW = 2

volume_types_str_lookup = {}

volume_types_str_lookup[ AUDIO_GLOBAL ] = 'global'
volume_types_str_lookup[ AUDIO_MEDIA_VIEWER ] = 'media viewer'
volume_types_str_lookup[ AUDIO_PREVIEW ] = 'preview'

volume_types_to_option_names = {}

volume_types_to_option_names[ AUDIO_GLOBAL ] = ( 'global_audio_mute', 'global_audio_volume' )
volume_types_to_option_names[ AUDIO_MEDIA_VIEWER ] = ( 'media_viewer_audio_mute', 'media_viewer_audio_volume' )
volume_types_to_option_names[ AUDIO_PREVIEW ] = ( 'preview_audio_mute', 'preview_audio_volume' )

def ChangeVolume( volume_type, volume ):
    
    ( mute_option_name, volume_option_name ) = volume_types_to_option_names[ volume_type ]
    
    HG.client_controller.new_options.SetInteger( volume_option_name, volume )
    
    HG.client_controller.pub( 'new_audio_volume' )
    
def FlipMute( volume_type ):
    
    ( mute_option_name, volume_option_name ) = volume_types_to_option_names[ volume_type ]
    
    HG.client_controller.new_options.FlipBoolean( mute_option_name )
    
    HG.client_controller.pub( 'new_audio_mute' )
    
def SetMute( volume_type, mute ):
    
    ( mute_option_name, volume_option_name ) = volume_types_to_option_names[ volume_type ]
    
    HG.client_controller.new_options.SetBoolean( mute_option_name, mute )
    
    HG.client_controller.pub( 'new_audio_mute' )
    
class AudioMuteButton( ClientGUICommon.BetterBitmapButton ):
    
    def __init__( self, parent, volume_type ):
        
        self._volume_type = volume_type
        
        pixmap = self._GetCorrectPixmap()
        
        ClientGUICommon.BetterBitmapButton.__init__( self, parent, pixmap, FlipMute, self._volume_type )
        
        HG.client_controller.sub( self, 'UpdateMute', 'new_audio_mute' )
        
    
    def _GetCorrectPixmap( self ):
        
        ( mute_option_name, volume_option_name ) = volume_types_to_option_names[ self._volume_type ]
        
        if HG.client_controller.new_options.GetBoolean( mute_option_name ):
            
            pixmap = CC.global_pixmaps().mute
            
        else:
            
            pixmap = CC.global_pixmaps().sound
            
        
        return pixmap
        
    
    def UpdateMute( self ):
        
        pixmap = self._GetCorrectPixmap()
        
        ClientGUIFunctions.SetBitmapButtonBitmap( self, pixmap )
        
    
class VolumeControl( QW.QWidget ):
    
    def __init__( self, parent, canvas_type, direction = 'down' ):
        
        QW.QWidget.__init__( self, parent )
        
        self._canvas_type = canvas_type
        
        self._global_mute = AudioMuteButton( self, AUDIO_GLOBAL )
        
        self._global_mute.setToolTip( 'Global mute/unmute' )
        
        vbox = QP.VBoxLayout( margin = 0, spacing = 0 )
        
        QP.AddToLayout( vbox, self._global_mute, CC.FLAGS_EXPAND_SIZER_BOTH_WAYS )
        
        self.setLayout( vbox )
        
        self._popup_window = self._PopupWindow( self, canvas_type, direction = direction )
        
    
    def enterEvent( self, event ):
        
        if not self.isVisible():
            
            return
            
        
        self._popup_window.DoShowHide()
        
        event.ignore()
        
    
    def leaveEvent( self, event ):
        
        if not self.isVisible():
            
            return
            
        
        self._popup_window.DoShowHide()
        
        event.ignore()
        
    
    class _PopupWindow( QW.QFrame ):
        
        def __init__( self, parent, canvas_type, direction = 'down' ):
            
            QW.QFrame.__init__( self, parent )
            
            self._canvas_type = canvas_type
            
            self._direction = direction
            
            self.setWindowFlags( QC.Qt.Tool | QC.Qt.FramelessWindowHint )
            
            self.setAttribute( QC.Qt.WA_ShowWithoutActivating )
            
            if self._canvas_type == ClientGUICommon.CANVAS_MEDIA_VIEWER:
                
                option_to_use = 'media_viewer_uses_its_own_audio_volume'
                volume_type = AUDIO_MEDIA_VIEWER
                
            else:
                
                option_to_use = 'preview_uses_its_own_audio_volume'
                volume_type = AUDIO_PREVIEW
                
            
            self._specific_mute = AudioMuteButton( self, volume_type )
            
            self._specific_mute.setToolTip( 'Mute/unmute: {}'.format( ClientGUICommon.canvas_str_lookup[ self._canvas_type ] ) )
            
            if HG.client_controller.new_options.GetBoolean( option_to_use ):
                
                slider_volume_type = volume_type
                
            else:
                
                slider_volume_type = AUDIO_GLOBAL
                
            
            self._volume = VolumeSlider( self, slider_volume_type )
            
            vbox = QP.VBoxLayout()
            
            if self._direction == 'down':
                
                QP.AddToLayout( vbox, self._specific_mute, CC.FLAGS_CENTER )
                QP.AddToLayout( vbox, self._volume, CC.FLAGS_CENTER )
                
            else:
                
                QP.AddToLayout( vbox, self._volume, CC.FLAGS_CENTER )
                QP.AddToLayout( vbox, self._specific_mute, CC.FLAGS_CENTER )
                
            
            #vbox.setAlignment( self._volume, QC.Qt.AlignHCenter )
            #vbox.setAlignment( self._specific_mute, QC.Qt.AlignHCenter )
            
            self.setLayout( vbox )
            
            self.hide()
            
            self.adjustSize()
            
        
        def DoShowHide( self ):
            
            parent = self.parentWidget()
            
            horizontal_offset = ( self.width() - parent.width() ) // 2 
            
            if self._direction == 'down':
                
                pos = parent.mapToGlobal( parent.rect().bottomLeft() )
                
            else:
                
                pos = parent.mapToGlobal( parent.rect().topLeft() - self.rect().bottomLeft() )
                
            
            pos.setX( pos.x() - horizontal_offset )
            
            self.move( pos )
            
            # QWidget.underMouse() doesn't work on the border edge and hence gives flicker, so just do it manually
            
            cursor_pos = QG.QCursor.pos()
            
            over_parent = parent.rect().contains( parent.mapFromGlobal( cursor_pos ) )
            over_me = self.rect().contains( self.mapFromGlobal( cursor_pos ) )
            
            should_show = over_parent or over_me
            
            if should_show:
                
                self.show()
                
            else:
                
                self.hide()
                
            
        
        def leaveEvent( self, event ):
            
            if not self.isVisible():
                
                return
                
            
            self.DoShowHide()
            
            event.ignore()
            
        
    
class VolumeSlider( QW.QSlider ):
    
    def __init__( self, parent, volume_type ):
        
        QW.QSlider.__init__( self, parent )
        
        self._volume_type = volume_type
        
        self.setOrientation( QC.Qt.Vertical )
        self.setTickInterval( 1 )
        self.setTickPosition( QW.QSlider.TicksBothSides )
        self.setRange( 0, 100 )
        
        volume = self._GetCorrectValue()
        
        self.setValue( volume )
        
        self.valueChanged.connect( self._VolumeSliderMoved )
        
    
    def _GetCorrectValue( self ):
        
        ( mute_option_name, volume_option_name ) = volume_types_to_option_names[ self._volume_type ]
        
        return HG.client_controller.new_options.GetInteger( volume_option_name )
        
    
    def _VolumeSliderMoved( self ):
        
        ChangeVolume( self._volume_type, self.value() )
        
    
    def UpdateMute( self ):
        
        volume = self._GetCorrectValue()
        
        self.setValue( volume )
        
    
