#! /usr/bin/env python
# -*- coding: iso8859-15 -*-

"""
Configuration de base des différents transpondeurs disponibles
"""

#Auteurs: Frédéric Pauget, Brice Dubost, Nicolas Dandrimont
#Licence : GPLv2

from commands import getoutput
from time import sleep
import os, socket

import textwrap

IP = socket.gethostbyaddr(socket.gethostname())[-1][0]

class CardBusy(Exception) :
    """ La carte est déja utilisée """

class NotRunning(Exception) :
    """ La carte ne diffuse rien """

class Card(object):
    """ Classe parent de toute classe de transpondeur """
    # Niveux de verbosite :
        # 0 : ne dit rien
        # 1 : messages à caractères informatifs
        # 2 : messages de debug
        # 3 : ne permet pas à mumudvb de daemonizer
    verbose = 3

    CONF_FILE = "/etc/sat/carte%i.conf" # %i : numero de la carte

    timeout_accord  =  20 #en secondes
    timeout_no_diff = 100 #en secondes

    srate = 0
    bandwidth = ""

    template_conf_TNT = textwrap.dedent("""\
    ### Fichier généré par /usr/scripts/tv/*
    ### Ne pas éditer !

    # Autoconfiguration complète
    autoconfiguration=2
    
    # Configuration multicast
    multicast_auto_join=1
    common_port=1234
    
    # Ne pas toucher aux chaines chiffrées
    dont_send_scrambled=1
    dvr_buffer_size=100
    
    # Configuration de la carte TNT
    freq=%(freq)i
    card=%(card)i
    bandwidth=%(bandwidth)s

    # Timeouts
    timeout_accord=%(timeout_accord)i
    timeout_no_diff=%(timeout_no_diff)i
    
    # Autoconfiguration des chaines
    autoconf_ip4=239.%(ip)s.%%card.%%number
    autoconf_lcn=1
    autoconf_name_template=TNT%%lcn %%name

    # Configuration SAP
    sap_organisation=crans
    sap_default_group=TNT
    """)


    template_conf_SAT = textwrap.dedent("""\
    ### Fichier généré par /usr/scripts/tv/*
    ### Ne pas éditer !

    # Autoconfiguration complète
    autoconfiguration=2
    
    # Configuration multicast
    multicast_auto_join=1
    common_port=1234
    
    # Ne pas toucher aux chaines chiffrées
    dont_send_scrambled=1
    dvr_buffer_size=100
    
    # Configuration de la carte Sat
    freq=%(freq)i
    pol=%(pol)s
    card=%(card)i
    srate=%(srate)i

    # Timeouts
    timeout_accord=%(timeout_accord)i
    timeout_no_diff=%(timeout_no_diff)i
    
    # Autoconfiguration des chaines
    autoconf_ip=239.%(ip)s.%%card.%%number
    autoconf_lcn=1
    autoconf_name_template=%%name

    # Configuration SAP
    sap_organisation=crans
    sap_default_group=%(sap)s
    """)

    template_conf_sid = textwrap.dedent("""\
    
    # Liste des chaines à diffuser
    autoconf_sid_list=%(sids)s
    """)

    def __cmp__(a,b) :
        for attr in ( 'card', 'freq', 'chaines' ) :
            if getattr(a,attr) != getattr(b,attr) :
                return -2
        return 0

    def __init__(self, card) :
        """ Initalisation card est le numéro (entier) de la carte
        correspondante """
        try :
            self.freq = int(self.__class__.__name__.split('_')[-1])
            self.pol = ''
        except ValueError:
            try:
                self.freq = int(self.__class__.__name__.split('_')[-1][:-1])
                self.pol = self.__class__.__name__.split('_')[-1][-1]
            except ValueError:
                # On ne pourra pas faire grand chose à part killer le flux de la carte
                self.freq = ''
                self.pol = ''
        self.classe = self.__class__.__name__.split('_')[0]
        self.card = card
        self.sap = self.classe

    def gen_conf(self) :
        """ Génère le fichier de conf """
        if not self.freq :
            if self.verbose > 1 : print "Instance ne permettant pas la génération de la conf"
            return

        fd = open(self.CONF_FILE % self.card,'w')
        # Entète du fichier
        fd.write( getattr(self, 'template_conf_%s' % self.classe) %
                  { 'bandwidth' : self.bandwidth,
                    'freq' : self.freq ,
                    'card' : self.card ,
                    'timeout_accord' : self.timeout_accord ,
                    'timeout_no_diff' : self.timeout_no_diff,
                    'pol': self.pol,
                    'sap': self.sap,
                    'srate': self.srate,
                    'ip': IP.split('.')[-1]} )
        if hasattr(self, 'sid_list'):
            fd.write(self.template_conf_sid %
                    { 'sids' : " ".join(str(sid) for sid in self.sid_list) })

        fd.close()

    def start(self) :
        """ Lance la diffusion """
        if not self.freq :
            if self.verbose > 1 : print "Instance ne permettant pas le lancement d'un flux"
            return

        if self.verbose >0 :
            print "Generation de la conf de %s sur la carte %i" % (self.__class__.__name__, self.card)

        self.gen_conf()
        if self.verbose >0 : print "    OK"

class TNT_base(Card) :
    """
    Classe de base pour les transpondeurs TNT. On pourra se référer au site du
    CSA pour une liste des fréquences. À Cachan, on capte l'émission de la Tour
    Eiffel.
    http://www.csa.fr/Media/Files/Television/La-reception/Liste-des-canaux-affectes-aux-multiplex-de-la-TNT-en-metropole-et-outre-mer
    """

    bandwidth="8MHz"
    
    @classmethod
    def freqByChannel(cls, channel):
        """
        Renvoie la fréquence (en MHz) correspondant à un canal donné.
        À titre indicatif.
        Voir la page perso:
        http://tvignaud.pagesperso-orange.fr/tv/canaux.htm
        """
        if channel < 21 or channel > 60:
            raise IndexError('Canal non utilisé en France')
        return 474. + (channel-21)*8

class TNT_R1_586000(TNT_base):
    """
    Canal: 35
    France 2, France 5, France Ô, LCP, France 3
    """
    pass

class TNT_R2_506000(TNT_base):
    """
    Canal: 25
    D8, BFM TV, i>TELE, D17, Gulli, France 4
    """
    pass

class TNT_R3_482000(TNT_base):
    """ 
    Canal: 22
    Note: Canal+ : pas de diffusion la plupart du temps...
    """
    timeout_no_diff=0

class TNT_R4_546000(TNT_base):
    """
    Canal: 30
    M6, W9, NT1, PARIS PREMIERE, ARTE HD
    """
    pass

class TNT_R5_530000(TNT_base):
    """
    Canal: 28
    TF1 HD, France 2 HD, M6HD
    """
    pass

class TNT_R6_562000(TNT_base):
    """
    Canal: 32
    TF1, NRJ12, TMC, ARTE
    """
    pass

class TNT_L8_570000(TNT_base):
    """
    Transpondeur local, aka R15.
    Canal: 33
    À Cachan, on reçoit:
    Canal 31, IDF1, NRJ Paris, BFM Business
    """
    pass


class TNT_R7_642000(TNT_base):
    """
    Canal: 42
    HD1, Équipe 21, Chérie 25
    """
    pass

class TNT_R8_770000(TNT_base):
    """
    Canal: 58
    6ter, Numero 23, RMC découverte
    """
    pass

class SAT_UK_base(Card):
    sap="UK"

class SAT_10773h(SAT_UK_base):
    """BBC"""
    srate = 22000

class SAT_10714h(SAT_UK_base):
    """Channel4"""
    srate = 22000
    sid_list = [
            9211, # Channel4
            9220, # Film4
            9225, # Film4 +1
            9230, # More4 +1
            ]

class SAT_11344h(SAT_UK_base):
    """Food Network"""
    srate = 27500
    sid_list = [ 53260, # Food Network
                 53270, # Food Network +1
                 53280, # wedding tv
                ]

class SAT_11895v(SAT_UK_base):
    """MTV"""
    srate = 27500

class SAT_12480v(SAT_UK_base):
    """Channel 4"""
    srate = 27500

class SAT_11343v(SAT_UK_base):
    """Sex"""
    srate = 27500

class SAT_11222h(SAT_UK_base):
    """Random"""
    srate = 27500
    sid_list = [
        52001, # UCB
        52002, # Horror channel +1
        #52004, Ummah
        52005, # Sony TV
        #52006, # Jewelry
        52007, #CBS Action
        #52008, # Get lucky (porn)
        52010, # Summer hits TV
        52014, # BT Sport 1
        #52040, # Sportxxxgirls (porn)
        #52050, # Northern Birds (porn)
        52056, # Controversial TV
        52060, # Heat (chaîne de musique)
        52065, # Magic (chaîne de musique)
        52070, # Klear TV (chaîne de musique)
        52085, # Muslim World
    ]
