# GstMini
# Copyright (C) 2025 Rafael Caricio <rafael@caricio.com>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Library General Public
# License as published by the Free Software Foundation; either
# version 2 of the License, or (at your option) any later version.
#
# This library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Library General Public License for more details.
#
# You should have received a copy of the GNU Library General Public
# License along with this library; if not, write to the
# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
# Boston, MA 02110-1301, USA.


import threading
from ..core.element import GstElement, GstState
from ..core.buffer import GstBuffer, BufferFlags
from ..core.pad import GstFlowReturn

# Element that reads data from a file and pushes it downstream.
class FileSrc(GstElement):
    """
    Source element that reads data from a file.

    Demonstrates file-based sources that read data and push it downstream.
    """

    def __init__(self, name: str, location: str, blocksize : int = 4096):
        """
        Create a file source.

        Args:
            name: Element name
            location: Path to the file to read
        """
        super().__init__(name)
        self.location = location
        self.blocksize = blocksize

        # Create source pad
        self.src_pad = self.create_src_pad("src")

    def on_playing(self):
        """Start reading from the file when entering PLAYING state."""
        self.log(f"Opening file: {self.location}")
        self._file = open(self.location, "rb")

        self._read_thread = threading.Thread(target=self._read_loop, daemon=True)
        self._read_thread.start()

    def on_null(self):
        """Stop reading from the file when entering NULL state."""
        self.log("Closing file source")
        if hasattr(self, "_file"):
            self._file.close()

    def _read_loop(self):
        """Read data from the file and push it downstream."""
        while self.state == GstState.PLAYING:
            data = self._file.read(self.blocksize)
            if not data:
                self.log("End of file reached")
                self.src_pad.push(GstBuffer(pts=0, duration=0, data=None, flags=BufferFlags.EOS))
                break

            pts = self.pipeline.clock.get_time()

            buffer = GstBuffer(pts=pts, duration=0, data=data)
            result = self.src_pad.push(buffer)
            if result != GstFlowReturn.OK:
                self.log(f"Failed to push buffer (result: {result})")
                break
