# Copyright (C) 2021-2022 J.F.Dockes
#   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.

import os
import subprocess
import threading

from upmplgutils import uplog, direntry, getOptionValue
import conftree

class UpmpdcliRadios(object):
    def __init__(self, upconfig):
        datadir = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
        if not os.path.isabs(datadir):
            datadir = "/usr/share/upmpdcli"
        self.fetchstream = os.path.join(datadir, "rdpl2stream", "fetchStream.py")
        self._radios = []
        self._readRadios(upconfig)
        #uplog("Radios: %s" % self._radios)

    def _fetchStream(self, index, title, uri, artUri, mime):
        uplog(f"upradios: Fetching {title}")
        streamUri=""
        try:
            streamUri = subprocess.check_output([self.fetchstream, uri])
            streamUri = streamUri.decode('utf-8').strip("\r\n")
        except Exception as ex:
            uplog("fetchStream.py failed for %s: %s" % (title, ex))
        if streamUri:
            self._radios[index] = (title, streamUri, uri, artUri, mime)
        
    def _readRadiosFromConf(self, conf):
        '''Read radio definitions from a config file (either main file or radiolist)'''
        keys = conf.getSubKeys_unsorted()
        threads = []
        cntt = 0
        for k in keys:
            if k.startswith("radio"):
                title = k[6:]
                uri = conf.get("url", k)
                artUri = conf.get("artUrl", k)
                mime = conf.get("mime", k)
                self._radios.append(None)
                idx = len(self._radios) - 1
                t = threading.Thread(target=self._fetchStream, args=(idx, title, uri, artUri, mime))
                t.start()
                threads.append(t)
                cntt += 1
                # Note that it's ok to join a thread multiple times, so we keep things simple
                if cntt >= self._maxthreads:
                    uplog(f"upradios: Waiting for threads")
                    for t in threads:
                        t.join()
                    uplog(f"upradios: Waiting done")
                    cntt = 0
        uplog(f"upradios: Waiting for threads")
        for t in threads:
            t.join()
        uplog(f"upradios: Waiting done")
        # Get rid of None entries in the list, keeping the order
        tlist = []
        for rd in self._radios:
            if rd:
                tlist.append(rd)
        self._radios = tlist
        uplog(f"upradios: Init done")
        
    def _readRadios(self, upconfig):
        '''Read radio definitions from main config file, then possible radiolist'''
        self._radios = []
        self._maxthreads = upconfig.get("upradiosmaxthreads")
        if self._maxthreads:
            self._maxthreads = int(self._maxthreads)
        else:
            self._maxthreads = 5
        self._readRadiosFromConf(upconfig)
        radiolist = getOptionValue("radiolist", "/usr/share/upmpdcli/radio_scripts/radiolist.conf")
        if radiolist:
            radioconf = conftree.ConfSimple(radiolist)
            self._readRadiosFromConf(radioconf)


    def __iter__(self):
       return RadioIterator(self)

    # Note: not implementing __getitem__ because don't want to deal with slices, neg indexes etc.
    def get_radio(self, idx):
        if idx < 0 or idx > len(self._radios):
            raise(IndexError(f"bad radio index {idx}"))
        radio = self._radios[idx]
        return {"index" : idx, "title" : radio[0], "streamUri" : radio[1],
                "uri" : radio[2], "artUri" : radio[3], "mime": radio[4]}
       
class RadioIterator:
   def __init__(self, radios):
       self._radios = radios
       self._index = 0

   def __next__(self):
       if self._index < (len(self._radios._radios)):
           result = self._radios.get_radio(self._index)
           self._index +=1
           return result

       raise StopIteration            


def radioToEntry(pid, id, radio):
    #uplog(f"radioToEntry: pid {pid} id {id}")
    # if this comes from a 'browse meta', the id is set, else compute it
    if id is None:
        objid = pid
        if objid[-1] != "$":
            objid += "$"
        objid += "e" + str(radio["index"])
    else:
        objid = id
    if "mime" in radio and radio["mime"]:
        mime = radio["mime"]
    else:
        mime = "audio/mpeg"
    return {
        'pid': pid,
        'id': objid,
        'uri': radio["streamUri"],
        'tp': 'it',
        'res:mime': mime,
        'upnp:class': 'object.item.audioItem.musicTrack',
        'upnp:albumArtURI': radio["artUri"],
        'tt': radio["title"],
        # This is for Kodi mostly, to avoid displaying a big "Unknown" placeholder
        'upnp:artist': "Internet Radio",
        'upnp:album': "upmpdcli"
    }

def radioIndexFromId(objid):
    stridx = objid.find("$e")
    if stridx == -1:
        raise Exception(f"Bad objid {objid}")
    return int(objid[stridx+2:])



if __name__ == "__main__":
    from upmplgutils import getConfigObject
    radios = UpmpdcliRadios(getConfigObject())
    for radio in radios:
        print("%s" % radio)
