#!/usr/bin/env python3
# -*- coding: utf-8 -*-

""" parlatype-example.py demonstrates libparlatype. """

import os
import sys
import gi
gi.require_version('Parlatype', '@API_VERSION@')
gi.require_version('Gtk', '4.0')
from gi.repository import Parlatype as Pt
from gi.repository import Gtk
from gi.repository import GObject


def error_message(message, parent):
    msg = Gtk.MessageDialog(parent=parent,
                            modal=True,
                            message_type=Gtk.MessageType.ERROR,
                            buttons=Gtk.ButtonsType.OK,
                            text=message)
    msg.present()


class ParlatypeExample(Gtk.Application):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.connect('activate', self.on_activate)

    def on_activate(self, app):
        self.player = Pt.Player.new()
        self.player.connect("error", self.player_error)
        self.player.connect("end-of-stream", self.player_end_of_stream)

        builder = Gtk.Builder()
        builder.add_from_file('parlatype-example.ui')

        self.win = builder.get_object('window')

        self.viewer = builder.get_object('waveviewer')
        self.player.connect_waveviewer(self.viewer)

        self.progress = builder.get_object('progress')
        self.viewer.connect('load-progress', self.update_progress)

        self.button = builder.get_object('button_play')
        self.button.connect('toggled', self.button_toggled)
        self.label = builder.get_object('pos_label')
        follow_cursor = builder.get_object('follow_cursor')
        GObject.GObject.bind_property(follow_cursor, "active",
                                      self.viewer, "follow-cursor",
                                      GObject.BindingFlags.BIDIRECTIONAL |
                                      GObject.BindingFlags.SYNC_CREATE)
        volumebutton = builder.get_object('volumebutton')
        GObject.GObject.bind_property(volumebutton, "value",
                                      self.player, "volume",
                                      GObject.BindingFlags.BIDIRECTIONAL |
                                      GObject.BindingFlags.SYNC_CREATE)
        pause = builder.get_object('pause_spin')
        pause.connect('value-changed', self.pause_value_changed)
        back = builder.get_object('back_spin')
        back.connect('value-changed', self.back_value_changed)
        forward = builder.get_object('forward_spin')
        forward.connect('value-changed', self.forward_value_changed)
        self.player.set_property("pause", pause.get_value() * 1000)
        self.player.set_property("back", back.get_value() * 1000)
        self.player.set_property("forward", forward.get_value() * 1000)
        self.timer = 0

        button_back = builder.get_object('button_jump_back')
        button_back.connect('clicked', self.back_clicked)

        button_forward = builder.get_object('button_jump_forward')
        button_forward.connect('clicked', self.forward_clicked)

        speed_scale = builder.get_object('speed_scale')
        speed_scale.connect('value-changed', self.speed_value_changed)

        show_ruler = builder.get_object('show_ruler')
        show_ruler.connect('toggled', self.show_ruler_toggled)
        fixed_cursor = builder.get_object('fixed_cursor')
        fixed_cursor.connect('toggled', self.fixed_cursor_toggled)

        open_button = builder.get_object('open_button')
        open_button.connect('clicked', self.filechooser)

        self.win.set_application(self)
        self.win.present()

    def update_progress(self, viewer, value):
        if value == 1:
            value = 0
        self.progress.set_fraction(value)

    def open_file(self, filename):
        try:
            self.player.open_uri(filename)
        except Exception as err:
            error_message(err.args[0], self.win)
            if self.timer > 0:
                self.viewer.remove_tick_callback(self.timer)
                self.timer = 0
            return
        # this could also fail, skip checking in this example
        self.viewer.load_wave_async(filename, None, None)
        self.timer = self.viewer.add_tick_callback(self.update_cursor)

    def filechooser_response(self, dialog, response):
        if response == Gtk.ResponseType.OK:
            file = dialog.get_file()
            self.open_file(file.get_uri())
        dialog.destroy()

    def filechooser(self, button):
        dialog = Gtk.FileChooserDialog(
            title="Please choose a file",
            parent=self.win,
            action=Gtk.FileChooserAction.OPEN)
        dialog.add_button("_Cancel", Gtk.ResponseType.CANCEL)
        dialog.add_button("_Open", Gtk.ResponseType.OK)
        dialog.connect("response",self.filechooser_response)
        dialog.present()

    def player_error(self, player, error):
        error_message(error.args[0], self.win)

    def player_end_of_stream(self, player):
        GObject.GObject.handler_block_by_func(self.button, self.button_toggled)
        self.button.set_active(False)
        GObject.GObject.handler_unblock_by_func(self.button, self.button_toggled)
        self.player.pause()

    def button_toggled(self, button):
        if button.get_active():
            self.viewer.set_property("follow-cursor", True)
            self.player.play()
        else:
            self.player.pause_and_rewind()

    def update_cursor(self, viewer, frame_clock):
        viewer.set_property("playback-cursor", self.player.get_position())
        text = self.player.get_current_time_string(
            Pt.PrecisionType.SECOND_10TH)
        # Sometimes the position can't be retrieved and None is returned.
        if (text):
            self.label.set_text(text)
        # Continue updating
        return True

    def show_ruler_toggled(self, button):
        self.viewer.set_property("show-ruler", button.get_active())

    def fixed_cursor_toggled(self, button):
        self.viewer.set_property("fixed-cursor", button.get_active())

    def speed_value_changed(self, gtkrange):
        self.player.set_speed(gtkrange.get_value())

    def pause_value_changed(self, gtkrange):
        self.player.set_property("pause", gtkrange.get_value() * 1000)

    def back_value_changed(self, gtkrange):
        self.player.set_property("back", gtkrange.get_value() * 1000)

    def forward_value_changed(self, gtkrange):
        self.player.set_property("forward", gtkrange.get_value() * 1000)

    def back_clicked(self, button):
        self.player.jump_back()

    def forward_clicked(self, button):
        self.player.jump_forward()

app = ParlatypeExample()
app.run(sys.argv)
