from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.behaviors import ButtonBehavior
from kivy.graphics.texture import Texture
from kivy.clock import Clock
from kivy.metrics import dp
from kivy.properties import StringProperty
import JsonUtl as jsonutil
import cv2
import threading



class ButtonImage(ButtonBehavior, Image):
    pass

class MainScreen(Screen):
    ServerListVar = jsonutil.OpenJsontoArray() 
    BtnId = 0
    DelBtnId = 0

    def __init__(self, **kw):
        super().__init__(**kw)
        for i in range (0,len(self.ServerListVar)):
            self.CreateButtons(i)

    def Clicked(self,widget):
        Adress = self.ids.StreamAdress
        if not Adress.text == "":
            self.ServerListVar.append(Adress.text.strip())
            jsonutil.SaveArraytoJson(self.ServerListVar)
            self.CreateButtons(len(self.ServerListVar)- 1)
            Adress.text = ""
    
    def CamSelectButtonPressed(self,x):
            app = App.get_running_app()
            app.data = self.ServerListVar[x]
            app.root.current = "Stream"  

    def CamDeleteButtonPressed(self,x):
        del self.ServerListVar[x]
        self.ids.CamSelectStackLayout.clear_widgets()
        jsonutil.SaveArraytoJson(self.ServerListVar)
        self.ServerListVar = jsonutil.OpenJsontoArray() 
        self.BtnId = 0
        self.DelBtnId = 0
        for i in range (0,len(self.ServerListVar)):
            self.CreateButtons(i)


    def CreateButtons(self, i):
        box = BoxLayout(size_hint=(None, None), width=dp(200), height=dp(200), orientation="vertical")
        bimage = ButtonImage(source = "ConnectionError.png")
        b2 = ButtonImage(size_hint=(None, None), width=dp(200), height=dp(50))
        b2.source = "DeleteButton.png"
        bimage.bind(on_press=lambda instance, button_id=self.BtnId: self.CamSelectButtonPressed(button_id))
        self.BtnId = self.BtnId + 1
        b2.bind(on_press=lambda instance, button_id=self.DelBtnId: self.CamDeleteButtonPressed(button_id))
        self.DelBtnId = self.DelBtnId + 1

        # call capture in a separate thread
        threading.Thread(target=self.capture_video, args=(self.ServerListVar[i], bimage)).start()
        box.add_widget(bimage)
        box.add_widget(b2)
        self.ids.CamSelectStackLayout.add_widget(box)


    def capture_video(self, url, widget):
        capture = cv2.VideoCapture(url, cv2.CAP_FFMPEG, [cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY])
        print(url)
        while True:
            # read the video frame within the thread
            ret, frame = capture.read()
            if ret:
                # update the widget texture on the main thread
                Clock.schedule_once(lambda dt: self.update_texture(frame, widget))
                break
            else:
                # release the capture and stop the thread if there’s an error
                capture.release()
                break


    def update_texture(self, frame, widget):
        buf = cv2.flip(frame, 0).tobytes()  
        texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt="bgr")
        texture.blit_buffer(buf, colorfmt="bgr", bufferfmt="ubyte")
        widget.texture = texture


class StreamView(Screen): 
    
    output = StringProperty() 
    #event = None
    def on_enter(self):
        app = App.get_running_app()
        self.output = app.data
        print("before calling cv capture")
        self.capture = cv2.VideoCapture(self.output, cv2.CAP_FFMPEG, [cv2.CAP_PROP_HW_ACCELERATION, cv2.VIDEO_ACCELERATION_ANY])  
        print("after calling cv capture")
        #b = Button(size_hint = (0.05, 0.05), pos_hint = {"top":1}, background_color = (1,0,0,1))
        b = ButtonImage(size_hint = (0.05, 1), pos_hint = {"top":1},source = "BackButton.png")
        b.bind(on_press=lambda instance, button_id="i": gotomainscreen(button_id))
        self.Box = BoxLayout()
        self.image = Image()

        self.add_widget(self.Box)
        print("before starting clock")
        self.event = Clock.schedule_interval(self.update, 1.0 / 30.0) 
        self.Box.add_widget(b)
        self.Box.add_widget(self.image)



        def gotomainscreen(x):
            app = App.get_running_app()
            app.root.current = "Main"

    def update(self, dt):
        ret, frame = self.capture.read()
        if ret:
            buf = cv2.flip(frame, 0).tobytes()  
            texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
            texture.blit_buffer(buf, colorfmt='bgr', bufferfmt='ubyte')
            self.image.texture = texture

    def on_leave(self):
        self.capture.release()
        self.event.cancel()
        self.Box.clear_widgets()
        cv2.destroyAllWindows()


class ScreenMan(ScreenManager):
    pass

class IPCAMApp(App):
    def build(self):
        sm = ScreenMan()
        sm.add_widget(MainScreen(name="Main"))
        sm.add_widget(StreamView(name="Stream"))
        sm.current = "Main" 
        return sm
    

if __name__ == "__main__":
    IPCAMApp().run()