#!/usr/bin/python3 -sP
# GPL. (C) 2026 Paolo Patruno.

# This program is free software; you can redistribute it and/or modify 
# it under the terms of the GNU General Public License as published by 
# the Free Software Foundation; either version 2 of the License, or 
# (at your option) any later version. 
# 
# This program 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 General Public License for more details. 
# 
# You should have received a copy of the GNU General Public License 
# along with this program; if not, write to the Free Software 
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
# 

VERSION="1.0"

from autoradio import multitrack
import optparse,sys
import subprocess,tempfile,os
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk,Gdk, GLib, Gio
from autoradio.autoplayer.playlist import Playlist
import logging

outname=None
f1=None
f2=None
f3=None
ff1=None
ff2=None
ff3=None

class FileChooserWindow(Gtk.Window):
    def __init__(self):

        super().__init__(title="Multichannel Assembler")

        vbox = Gtk.VBox(spacing=6)
        self.add(vbox)
        
        box1 = Gtk.HBox(spacing=6)

        button1 = Gtk.Button(label="Choose File ER")
        button1.connect("clicked", self.on_file_clicked,"ER")
        box1.add(button1)

        button2 = Gtk.Button(label="Choose File LO")
        button2.connect("clicked", self.on_file_clicked,"LO")
        box1.add(button2)

        button3 = Gtk.Button(label="Choose File TO")
        button3.connect("clicked", self.on_file_clicked,"TO")
        box1.add(button3)

        vbox.pack_start(box1, False, True, 0)
        #self.add(box1)

        box2 = Gtk.HBox(spacing=6)

        buttonf1 = Gtk.Button(label="Choose File filler ER")
        buttonf1.connect("clicked", self.on_file_clicked,"FER")
        box2.add(buttonf1)

        buttonf2 = Gtk.Button(label="Choose File filler LO")
        buttonf2.connect("clicked", self.on_file_clicked,"FLO")
        box2.add(buttonf2)

        buttonf3 = Gtk.Button(label="Choose File filler TO")
        buttonf3.connect("clicked", self.on_file_clicked,"FTO")
        box2.add(buttonf3)

        vbox.pack_start(box2, False, True, 0)
        #self.add(box2)

        box3 = Gtk.HBox(spacing=6)
        
        button4 = Gtk.Button(label="Save multichannel")
        button4.set_name("save")
        button4.connect("clicked", self.on_file_save_clicked)
        box3.add(button4)

        button5 = Gtk.Button(label="Assemble")
        button5.set_name("assemble")
        button5.connect("clicked", self.on_assemble)
        box3.add(button5)
        
        vbox.pack_start(box3, False, True, 0)
        #self.add(box3)


    def on_assemble(self, widget):
        global f1,f2,f3,ff1,ff2,ff3, outname

        print("Assemble")
        if None in (f1,f2,f3,ff1,ff2,ff3,outname):
            print ("ERRORE")
            print(f1,f2,f3,ff1,ff2,ff3,outname)

            style_provider = Gtk.CssProvider()
            style_provider.load_from_data(b'''
            #assemble { background: #f55; }
            '''
                                          )
            # Applicare lo stile
            Gtk.StyleContext.add_provider_for_screen(
                Gdk.Screen.get_default(),
                style_provider,
                Gtk.STYLE_PROVIDER_PRIORITY_USER
            )
            widget.set_label("Errore")

            return

        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b'''
        #assemble { background: #aaf; }
        '''
                                      )
        # Applicare lo stile
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(),
            style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_USER
        )
        widget.set_label("Running")

        Gio.io_scheduler_push_job(self.assemble, widget, GLib.PRIORITY_DEFAULT,None)
        
        #Gtk.main_quit()


    def assemble(self,job, cancellable, widget):
        
        try:
            
            #playlists=["file:/"+f1,"file:/"+f2,"file:/"+f3]
            #filler_playlists=["file:/"+ff1,"file:/"+ff2,"file:/"+ff3]

            playlists=[f1,f2,f3]
            filler_playlists=[ff1,ff2,ff3]


            # apply replaygain to playlist
            p=[]
            for playlistname in playlists:
                p.append(Playlist([playlistname]))
            for pl in p:
                for element in pl:
                    metadata=element.get_metadata()
                    subprocess.check_call(["/usr/bin/rsgain","custom","-s","i",metadata["path"][6:]])
            
            # apply replaygain to filler
            p=[]
            for playlistname in filler_playlists:
                p.append(Playlist([playlistname]))
            for pl in p:
                for element in pl:
                    metadata=element.get_metadata()
                    subprocess.check_call(["/usr/bin/rsgain","custom","-s","i",metadata["path"][6:]])
            
            filename, extension = os.path.splitext(outname)

            if extension in (".ogg",".oga",".Ogg",".Oga",".OGG",".OGA"):

                with tempfile.TemporaryDirectory() as tmp:
                    path = os.path.join(tmp, 'assembler.flac')
                    multitrack.assemble_playlists(playlists,filler_playlists,path,artist="assemblatore",title="3 canali")
                    ## sox output.wav -b 16 output1.wav mcompand "0.005,0.1 -47,-40,-34,-34,-17,-33" 100 "0.003,0.05 -47,-40,-34,-34,-17,-33" 400 "0.000625,0.0125 -47,-40,-34,-34,-15,-33" 1600 "0.0001,0.025 -47,-40,-34,-34,-31,-31,-0,-30" 6400 "0,0.025 -38,-31,-28,-28,-0,-25"
                    ## sox output.wav -b 16 output1.wav compand 0.3,1 6:-70,-60,-20 -5 -90 0.2
                    ## oggenc  --advanced-encode-option disable_coupling -o outname path
                    subprocess.check_call(["/usr/bin/oggenc","--advanced-encode-option","disable_coupling","-o",outname,path])
            elif extension in (".flac",".Flac",".FLAC"):
                multitrack.assemble_playlists(playlists,filler_playlists,outname,artist="assemblatore",title="3 canali")
            else:
                logging.error("output file extension is not supported")
                raise RuntimeError("output file extension is not supported")
                  
        except:

            widget.set_label("Errore")

            style_provider = Gtk.CssProvider()
            style_provider.load_from_data(b'''
            #assemble { background: #f55; }
            '''
                                          )
            # Applicare lo stile
            Gtk.StyleContext.add_provider_for_screen(
                Gdk.Screen.get_default(),
                style_provider,
                Gtk.STYLE_PROVIDER_PRIORITY_USER
            )

            return

        style_provider = Gtk.CssProvider()
        style_provider.load_from_data(b'''
        #assemble { background: #5F5; }
        '''
                                      )
        # Applicare lo stile
        Gtk.StyleContext.add_provider_for_screen(
            Gdk.Screen.get_default(),
            style_provider,
            Gtk.STYLE_PROVIDER_PRIORITY_USER
        )
        
        widget.set_label("Done")
        
        
    def on_file_save_clicked(self, widget):

        global outname
        
        dialog = Gtk.FileChooserDialog(
            title="Please choose a file", parent=self, action=Gtk.FileChooserAction.SAVE)

        dialog.add_buttons(
            Gtk.STOCK_CANCEL,
            Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN,
            Gtk.ResponseType.OK,
        )

        response = dialog.run()
        
        if response == Gtk.ResponseType.OK:
            print("Save clicked")
            print("File selected: " + dialog.get_filename())
            outname=dialog.get_filename()
            
            widget.set_label(outname)

            style_provider = Gtk.CssProvider()
            style_provider.load_from_data(
                b'''#save { background: #5f5; }'''
            )
            # Applicare lo stile
            Gtk.StyleContext.add_provider_for_screen(
                Gdk.Screen.get_default(),
                style_provider,
                Gtk.STYLE_PROVIDER_PRIORITY_USER
            )
            
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")
        dialog.destroy()

        

    def on_file_clicked(self, widget,channel):
 
        global f1,f2,f3,ff1,ff2,ff3
       
        dialog = Gtk.FileChooserDialog(
            title="Please choose a file", parent=self, action=Gtk.FileChooserAction.OPEN)

        dialog.add_buttons(
            Gtk.STOCK_CANCEL,
            Gtk.ResponseType.CANCEL,
            Gtk.STOCK_OPEN,
            Gtk.ResponseType.OK,
        )

        self.add_filters(dialog)
        
        response = dialog.run()

        widget.set_name(channel)
        if response == Gtk.ResponseType.OK:
            print("Open clicked")
            print("File selected: " + dialog.get_filename())
            print(channel)

            widget.set_label(dialog.get_filename())

            style_provider = Gtk.CssProvider()
            style_provider.load_from_data(
                b'#' + channel.encode('UTF-8') + b' { background: #5f5; }'
            )
            # Applicare lo stile
            Gtk.StyleContext.add_provider_for_screen(
                Gdk.Screen.get_default(),
                style_provider,
                Gtk.STYLE_PROVIDER_PRIORITY_USER
            )

            if channel == "ER":
                f1=dialog.get_filename()
            elif channel == "LO":
                f2=dialog.get_filename()
            elif channel == "TO":
                f3=dialog.get_filename()
            elif channel == "FER":
                ff1=dialog.get_filename()
            elif channel == "FLO":
                ff2=dialog.get_filename()
            elif channel == "FTO":
                ff3=dialog.get_filename()
                
        elif response == Gtk.ResponseType.CANCEL:
            print("Cancel clicked")
        dialog.destroy()

    def add_filters(self, dialog):
        filter_m3u = Gtk.FileFilter()
        filter_m3u.set_name("m3u playlists")
        filter_m3u.add_pattern("*.m3u")
        dialog.add_filter(filter_m3u)

        filter_xspf = Gtk.FileFilter()
        filter_xspf.set_name("xspf playlists")
        filter_xspf.add_pattern("*.xspf")
        dialog.add_filter(filter_xspf)

        filter_any = Gtk.FileFilter()
        filter_any.set_name("Any files")
        filter_any.add_pattern("*")
        dialog.add_filter(filter_any)



def main():

    import logging
    logging.basicConfig(level=logging.DEBUG)

    global f1,f2,f3,ff1,ff2,ff3, outname

    p = optparse.OptionParser(usage="usage: %prog",
                              description="%prog assemble playlist for multichannel emission ",version="%prog "+VERSION)
    args = sys.argv
    if args is not None:
        p.parse_args(args)
        if len(args) > 1:
            sys.exit(1)
    
    #playlists=["test/er.m3u"
    #           ,"test/lo.m3u"
    #           ,"test/to.m3u"]
    #filler_playlists=["one_channel_filler.m3u"
    #                  ,"one_channel_filler.m3u"
    #                  ,"one_channel_filler.m3u"]
    #outname="test/multichannel.ogg"
    #
    #with tempfile.TemporaryDirectory() as tmp:
    #    path = os.path.join(tmp, 'assembler.flac')
    #    multitrack.assemble_playlists(playlists,filler_playlists,path,artist="assemblatore",title="3 canali")
    #    subprocess.check_call(["/usr/bin/oggenc","--advanced-encode-option","disable_coupling","-o",outname,path])
    #
    #multitrack.assemble_playlists(playlists,filler_playlists,outname,artist="assemblatore",title="3 canali")
    #
    #sys.exit(0)

    win = FileChooserWindow()
    win.connect("destroy", Gtk.main_quit)
    win.show_all()
    Gtk.main()


    if None in (f1,f2,f3,ff1,ff2,ff3,outname):
        print ("ERRORE")
        print(f1,f2,f3,ff1,ff2,ff3,outname)
        sys.exit(1)
        
        
if __name__ == '__main__':
    main()  # (this code was run as script)
    
