import os
import sys
import time
import threading

from appPublic.sockPackage import get_free_local_addr
from kivy.utils import platform
from traceback import print_exc
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.video import Video
from kivy.uix.slider import Slider
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.filechooser import FileChooserListView
from kivy.uix.label import Label
from kivy.app import App
from kivy.clock import Clock
from kivy.logger import Logger

from kivy.properties import ObjectProperty, StringProperty, BooleanProperty, \
    NumericProperty, DictProperty, OptionProperty
from pythonosc import dispatcher, osc_server
from ffpyplayer.tools import set_log_callback
from .utils import *
from .paging import PageLoader
from .baseWidget import PressableImage
from .swipebehavior import SwipeBehavior

desktopOSs=[
	"win",
	"linux",
	"macosx"
]

logger_func = {'quiet': Logger.critical, 'panic': Logger.critical,
               'fatal': Logger.critical, 'error': Logger.error,
               'warning': Logger.warning, 'info': Logger.info,
               'verbose': Logger.debug, 'debug': Logger.debug}

othersplatforms=['ios','android']

class BaseVPlayer(FloatLayout):
	fullscreen = BooleanProperty(False)
	def __init__(self,vfile=None,loop=None,mute=False):
		FloatLayout.__init__(self)
		self.loop = loop
		self.muteFlg = mute
		self.register_event_type('on_source_error')
		self.register_event_type('on_next')
		self.register_event_type('on_previous')
		Window.allow_screensaver = False
		self._video = Video(allow_stretch=True)
		self.add_widget(self._video)
		self.nextdir = None
		self.playlist = []
		self.curplay = 0
		self.old_volume = 0
		self._video.bind(state=self.on_state)
		# self._video.bind(loaded=self.playVideo) no effect
		self._video.bind(position=self.positionChanged)
		if loop:
			self.eos = 'loop'
		
		# self.bind(on_swipe_down=self.previous)
		# self.bind(on_swipe_up=self.next)
		set_log_callback(self.ffplayerLog)
		if hasattr(self._video._video, '_ffplayer'):
			self.ffplayer = self._video._video._ffplayer
		if vfile is not None:
			self.setSource(vfile)

	def on_size(self,*args):
		self._video.size = self.size
		print('****on_size()****',self.pos,self.size,self._video.pos,self._video.size)
	
	def positionChanged(self,o,v):
		if self.muteFlg:
			self._video.volume = 0

	def playVideo(self,o=None,v=None):
		# print('-------------VPlayer():playVideo()')
		self._video.state = 'play'
		self.nextdir = None

	def setSource(self,s):
		self.stop()
		self.curplay = 0
		self.playlist = [s]
		self._video.source = self.playlist[self.curplay]
		Logger.info('kivyblocks: Vplayer().setSource,s=%s',s)
		self.playVideo()

	def on_source_error(self,o,v):
		Logger.info('safecorner: {} error'.format(v))

	def on_next(self,o=None, v=None):
		pass

	def on_previous(self, o=None, v=None):
		pass

	def ffplayerLog(self, msg, level):
		msg = msg.strip()
		if msg:
			logger_func[level]('yffpyplayer: {}'.format(msg))
		if level == 'error' and self._video.source in msg:
			self.dispatch('on_source_error',self,self._video.source)

	def play(self,o=None,v=None):
		if self.curplay >= 0:
			self._video.source = self.playlist[self.curplay]
			self._video.state = 'play'
		else:
			Logger.info('VPlaer: self.curpay < 0')
			
	def next(self,o=None,v=None):
		self.nextdir = 'down'
		self.stop()
		self.dispatch('on_next',self)

	def previous(self,o=None,v=None):
		self.nextdir = 'up'
		self.stop()
		self.dispatch('on_previous',self)

	def on_state(self,o=None,v=None):
		if self._video.state == 'play':
			Window.allow_screensaver = False
		else:
			Window.allow_screensaver = True
		if self._video.state == 'stop':
			Logger.info('VPlayer: state==stop,nextdir=%s',self.nextdir)
			if self.nextdir is None:
				self.dispatch('on_next',self)
			self.nextdir = None

	def on_fullscreen(self, instance, value):
		window = self.get_parent_window()
		if not window:
			Logger.warning('VideoPlayer: Cannot switch to fullscreen, '
						   'window not found.')
			if value:
				self.fullscreen = False
			return
		if not self.parent:
			Logger.warning('VideoPlayer: Cannot switch to fullscreen, '
						   'no parent.')
			if value:
				self.fullscreen = False
			return

		if value:
			Window.fullscreen = True

			self._fullscreen_state = state = {
				'parent': self.parent,
				'pos': self.pos,
				'size': self.size,
				'pos_hint': self.pos_hint,
				'size_hint': self.size_hint,
				'window_children': window.children[:]}

			if platform in desktopOSs:
				Window.maximize()
			# remove all window children
			for child in window.children[:]:
				window.remove_widget(child)

			# put the video in fullscreen
			if state['parent'] is not window:
				state['parent'].remove_widget(self)
			window.add_widget(self)

			# ensure the video widget is in 0, 0, and the size will be
			# readjusted
			self.pos = (0, 0)
			self.size = (100, 100)
			self.pos_hint = {}
			self.size_hint = (1, 1)
		else:
			Window.fullscreen = False
			state = self._fullscreen_state
			window.remove_widget(self)
			for child in state['window_children']:
				window.add_widget(child)
			self.pos_hint = state['pos_hint']
			self.size_hint = state['size_hint']
			self.pos = state['pos']
			self.size = state['size']
			if state['parent'] is not window:
				state['parent'].add_widget(self)
			if platform in desktopOSs:
				Window.restore()

	def endplay(self,btn=None):
		self._video.seek(1.0,precise=True)

	def replay(self,btn=None):
		self._video.seek(0.0,precise=True)

	def audioswitch(self,btn=None):
		x = self._video._video._ffplayer.request_channel('audio')

	def setVolume(self,obj,v):
		self._video.volume = v
		if v >= 0.01:
			self.muteFlg = False
		else:
			self.muteFlg = True

	def setPosition(self,obj,v):
		self._video.seek(v)

	def mute(self,btn=None):
		if self._video.volume > 0.001:
			self.old_volume = self._video.volume
			self._video.volume = 0.0
		else:
			self._video.volume = self.old_volume

	def stop(self):
		self._video.unload()

	def pause(self,t=None):
		if self._video.state == 'play':
			self._video.state = 'pause'
		else:
			self._video.state = 'play'

	def __del__(self):
		self.stop()
	
class Swipe_VPlayer(BaseVPlayer, SwipeBehavior):
	def __init__(self,vfile=None, loop=False, mute=False):
		BaseVPlayer.__init__(self,vfile=vfile, loop=loop, mute=mute)
		SwipeBehavior.__init__(self)
		self.bind(on_swipe_down=self.previous)
		self.bind(on_swipe_up=self.next)

class OSC_VPlayer(BaseVPlayer):
	def __init__(self,vfile=None, loop=False, mute=False):
		self.dispatcher = dispatcher.Dispatcher()
		self.ip,self.port = get_free_local_addr()
		self.server = osc_server.ThreadingOSCUDPServer( (self.ip,self.port), 
									self.dispatcher)
		BaseVPlayer.__init__(self,vfile=vfile, loop=loop, mute=mute)
		self.map('/mute',self.mute)
		self.map('/pause',self.pause)
		self.map('/atrack',self.audioswitch)
		self.map('/endplay',self.endplay)
		self.map('/replay',self.replay)
		self.map('/next',self.next)
		self.map('/previous',self.previous)
		t = threading.Thread(target=self.server.serve_forever)
		t.daemon_threads = True
		t.start()

	def osc_server_quit(self):
		self.server.shutdown()
		self.server.server_close()

	def __del__(self):
		print("*******************VPlayer deleted**********")
		self.quit()

	def map(self,p,f):
		self.dispatcher.map(p,f,None)

	def get_osc_info(self):
		return {
			"host":self.ip,
			"port":self.port
		}


class VPlayer(Swipe_VPlayer):
	def __init__(self,vfile=None, loop=False,mute=False, opbar=True):
		self.opbar = opbar
		self.menubar = None
		self._popup = None
		self.menu_status = False
		self.manualMode = False
		self.pb = None
		super().__init__(vfile=vfile,loop=loop,mute=mute)
		self._video.bind(on_touch_down=self.show_hide_menu)
	
	def totime(self,dur):
		h = dur / 3600
		m = dur % 3600 / 60
		s = dur % 60
		return '%02d:%02d:%02d' % (h,m,s)
		
	def createProgressBar(self):
		if self.pb is None:
			self.pb = BoxLayout(orientation='horizontal',
				size_hint = (0.99,None),height=CSize(1.4))
			self.curposition = Label(text='0',width=CSize(4),
				size_hint_x=None)
			self.curposition.align='right'
			self.maxposition = Label(text=self.totime(self._video.duration),
				width=CSize(4),size_hint_x=None)
			self.maxposition.align = 'left'
			self.slider = Slider(min=0, 
				max=self._video.duration, 
				value=0, 
				orientation='horizontal', 
				step=0.01)
			self.slider.bind(on_touch_down=self.enterManualMode)
			self.slider.bind(on_touch_up=self.endManualMode)
			self.manual_mode=False

			self.pb.add_widget(self.curposition)
			self.pb.add_widget(self.slider)
			self.pb.add_widget(self.maxposition)
			self.menubar.add_widget(self.pb)

	def enterManualMode(self,obj,touch):
		if not self.slider.collide_point(*touch.pos):
			return
		self.manualMode = True

	def endManualMode(self,obj,touch):
		if not self.manualMode:
			return
		if self._video.duration < 0.0001:
			return
		self._video.seek(self.slider.value/self._video.duration)
		self.manualMode = False

	def positionChanged(self,o,v):
		self.update_slider(None)

	def update_slider(self,t):
		if self._video.state != 'play':
			return
		if self.pb is None:
			return
		v = self._video.position
		if v is None:
			return
		self.curposition.text = self.totime(v)
		if not self.manualMode:
			self.slider.value = v
			self.slider.max = self._video.duration
		self.maxposition.text = self.totime(self._video.duration)

	def __del__(self):
		self.stop()

	def beforeDestroy(self):
		print('beforeDestroy() called')
		self.stop()
		return True

	def show_hide_menu(self,obj,touch):
		if not self.collide_point(*touch.pos):
			print('not inside the player',touch.pos,self.pos,self.size)
			return 

		if touch.is_double_tap:
			self.fullscreen = False if self.fullscreen else True
			print('doube_tap')
			return 

		if not self.opbar:
			return

		if not self.menubar:
			self.buildMenu()
			return

		if self.menu_status:
			self.remove_widget(self.menubar)
		else:
			self.add_widget(self.menubar)
		self.menu_status = not self.menu_status

	def buildMenu(self):
		self.menubar = BoxLayout(orientation='horizontal',
			size_hint_y=None,height=CSize(1.4))
		self.btn_pause = PressableImage(source=blockImage('pause.png'),
					size_hint=(None,None),
					size=CSize(3,3)
		)
		if self._video.state == 'pause':
			self.btn_pause.source = blockImage('play.png')
		self.btn_pause.bind(on_press=self.pause)
		self.menubar.add_widget(self.btn_pause)
		"""
		self.btn_mute = PressableImage(source=blockImage('mute.png'),
					size_hint=(None,None),
					size=CSize(3,3)
		)
		self.btn_mute.bind(on_press=self.mute)
		self.menubar.add_widget(self.btn_mute)
		"""
		btn_cut = PressableImage(source=blockImage('next.png'),
				size_hint=(None,None),
				size=CSize(3,3)
		)
		btn_cut.bind(on_press=self.endplay)
		self.menubar.add_widget(btn_cut)
		btn_replay = PressableImage(source=blockImage('replay.png'),
				size_hint=(None,None),
				size=CSize(3,3)
		)
		btn_replay.bind(on_press=self.replay)
		self.menubar.add_widget(btn_replay)

		self.btn_audioswitch = PressableImage( \
					source=blockImage('musictrack.png'),
				size_hint=(None,None),
				size=CSize(3,3)
		)
					
		self.btn_audioswitch.bind(on_press=self.audioswitch)
		self.menubar.add_widget(self.btn_audioswitch)
		slider = Slider(min=0,
                                max=1,
                                value=self._video.volume,
                                orientation='horizontal',
								size_hint=(None,None),
								height = CSize(2),
								width = CSize(10),
                                step=0.07)
		slider.bind(on_touch_up=self.setVolume)
		self.menubar.add_widget(slider)
		self.menubar.pos = CSize(0,0)
		self.createProgressBar()
		self.add_widget(self.menubar)
		self.menu_status = True

	def setVolume(self,obj,v=None):
		BaseVPlayer.setVolume(self,obj,obj.value)

	def mute(self,btn):
		BaseVPlayer.mute(self,btn)
		if self.menubar:
			if self._video.volume < 0.001:
				btn.source = blockImage('volume.png')
			else:
				btn.source = blockImage('mute.png')

	def pause(self,t=None):
		BaseVPlayer.pause(self,t)
		if self.menubar:
			if self._video.state == 'pause':
				self.btn_pause.source  = blockImage('play.png')
			else:
				self.btn_pause.source = blockImage('pause.png')

if __name__ == '__main__':
	class MyApp(App):
		def build(self):
			vf = None
			if len(sys.argv) > 1:
				vf = sys.argv[1:]
			self.player = VPlayer(vfile=vf,
				loop=True,
				can_openfile=True,
				can_move = True,
				can_cut=True,
				can_replay=True,
				can_changevolume = True
			)
			return self.player

	MyApp().run()
