/*********************************
 * TvOnResel 0.1a
 * La classe principale TvOnResel
 * repr?sente la fen?tre principale
 *********************************/

import java.awt.*;
import javax.swing.*;
import javax.swing.event.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import java.util.regex.*;
import java.net.*;

public class TvOnResel extends JFrame
{   
                
        /*Composants de l'interface*/
        
        //repr?sente l'objet TvOnResel ( = this )
        JFrame frameComplete;
        
        //onglets
        JTabbedPane onglets;
        
        //Onglet principal
        JButton regarder;
        JButton enregistrer;
        JButton programmer;
        JLabel labelEnCours;
        JList listeAff;
        
        //onglet enregistrements
        JButton arrEnr;
        JButton lireEnr;
        JButton progFinEnr;
        JList listeAffEnr;
        
        //onglet programmations
        JButton nouvProg;
        JButton arretEnrProg;
        JButton supprProg;
        JList listeAffProg;
        
        //onglet fichiers
        JButton lireFic;
        JButton supprFic;
        JButton majListeFic;
        JList listeAffFic;
        
        //onglet options
        JButton enrOptions;
        JButton majListeChaines;
        JButton majProg;
        JButton choixFicVlc;
        JButton choixFicEnregistrements;
        JTextField champChmVlc;
        JTextField champChmEnregistrements;
                        
        /* Configuration en "dur" */
        public final static String versionLog = "0.32a";
        public final static String nomLog = "TvOnResel";
        public final static String nomFicOptions = "config.txt";
        final String sepDoss = System.getProperty( "file.separator" );
        final Dimension tailleFen = new Dimension( 600, 350 );
        final String chmFicExec = System.getProperty( "java.class.path" );
        String dossierExec; //dossier d'execution a remplir
        
        /* variables de fonctionnement */
        
        //les listes a l'affichage sont-elles initialisees ?
        boolean listeAffEnrOk = false;
        boolean listeAffFicOk = false;
        boolean listeAffProgOk = false;
        
        //timer pour surveiller les enregistrements en cours
        javax.swing.Timer timerSurvEnr;
        
        //represente la liste des chaines
        Vector listeChaines = new Vector();
        
        //repr?sente la lecture en cours (thread)
        LectureEnCours lectureEnCours = new LectureEnCours();
        
        //repr?sente les enregistrements en cours (vecteur de threads)
        Vector enrEnCours = new Vector();
        
        //represente les programmations en cours (vecteur de threads)*/
        Vector listeProgrammes = new Vector();
        
        //represente la liste des fichiers
        Vector listeFic = new Vector();
        
        /* Configuration du fichier de config */
        
        //fichier liste des chaines
        String nomFicChaines = "listeChaines.m3u";
        
        //fichier liste des programmations
        String nomFicProgrammations = "programmations.xml";
        
        //chemin vers VLC
        String chmVlc = "vlc";
        
        //chemin ou enregistrer les enregistrements
        String chmEnregistrements = System.getProperty( "user.home" );
        
        //url de la liste des chaines distante
        String urlListeChaines = "http://twisterss.free.fr/TvOnResel/listeChainesResel.m3u";
        
        //url d'infos de maj
        String urlInfosMaj = "http://twisterss.free.fr/TvOnResel/infosMaj.txt";
        
        //extention des enregistrements
        String extVideo = ".mpeg";
        
        //temps entre les verifications pour les enregistrements (secondes)
        int tempsInterVerif = 5;
        
        //premier demarrage ?
        boolean premierDemarrage = true;
        
/*********************************************
 *Creation de l'interface
 *et initialiation
 *********************************************/

/* initialisation */
        
        //procedure d'initialisation
        public static void main(String[] args)
        {                                                
                //Affichage du demarrage
                System.out.println( nomLog + " " + versionLog );
                
                //Cr?ation de l'objet fen?tre principale
                new TvOnResel();
        }
        
        //Constructeur de la fen?tre principale
        TvOnResel()
        {
                
                //Creation de la fenetre
                super( nomLog + " " + versionLog );
                
                frameComplete = this;
                
                //localisation du dossier actuel d'execution
                File ficExec = new File( chmFicExec );
                try
                {
                        if( ficExec.isDirectory() )
                                dossierExec = ficExec.getCanonicalPath();
                        else
                                dossierExec = ficExec.getParentFile().getCanonicalPath();
                }
                catch( Exception e )
                {
                        System.out.println( "impossible de localiser le dossier actuel" );
                        dossierExec = System.getProperty( "user.home" );
                }
                
                //Recuperation des options
                lireOptions();
                
                //Evenement de fermeture
                WindowListener fermeture = new WindowAdapter()
                {
                        public void windowClosing(WindowEvent e)
                        {
                                sortir();
                        }
                };
                addWindowListener( fermeture );
                                
                //Lecture de la liste de lecture
                lireListeChaines();
                            
                //Creation de l'onglet principal
                JPanel panelPrincipal = fairePanelPrincipal();
                
                //Creation de l'onglet options
                JPanel panelOptions = fairePanelOptions();
                
                //Creation de l'onglet enregistrements
                JPanel panelEnregistrements = fairePanelEnregistrements();
                
                //Creation de l'onglet fichiers
                JPanel panelFichiers = fairePanelFichiers();
                
                //Creation de l'onglet programmations
                JPanel panelProgrammes = fairePanelProgrammes();
                
                //Separation en onglets
                onglets = new JTabbedPane( SwingConstants.TOP );
                onglets.addTab( "Principal", panelPrincipal );
                onglets.addTab( "Enregistrements", panelEnregistrements );
                onglets.addTab( "Programmations", panelProgrammes );
                onglets.addTab( "Fichiers", panelFichiers );
                onglets.addTab( "Configuration", panelOptions );
                
                //Panel contenant tout le reste
                JPanel panelGlobal = new JPanel();
                panelGlobal.setLayout( new BorderLayout() );
                panelGlobal.add( onglets, BorderLayout.CENTER );
                
                //Affichage de la fen?tre
                setContentPane( panelGlobal );
                setSize( tailleFen );
                setVisible(true);
                
                //Gestion du premier demarrage
                if( premierDemarrage )
                {
                        //selection onglet options
                        onglets.setSelectedIndex( 4 );
                        
                        //config par defaut selon systeme d'exploitation
                        String systeme = System.getProperty( "os.name" );
                        Pattern masqueWin = Pattern.compile( "windows" );
                        Matcher trouveurWin = masqueWin.matcher( systeme.toLowerCase() );
                        try
                        {
                                if( trouveurWin.find() )
                                {
                                    chmVlc = ( new File( "C:\\Program Files\\VideoLAN\\VLC\\vlc.exe" ) ).getCanonicalPath();
                                }
                                else
                                {
                                    chmVlc = ( new File( "/usr/bin/vlc" ) ).getCanonicalPath();
                                }
                                File dossEnr = new File( dossierExec + sepDoss + "enregistrements" );
                                //creation du dossier si non existant
                                if(! dossEnr.isDirectory() )
                                        dossEnr.mkdir();
                                chmEnregistrements = dossEnr.getCanonicalPath();
                                
                                champChmVlc.setText( chmVlc );
                                champChmEnregistrements.setText( chmEnregistrements );
                                premierDemarrage = false;
                                enregistrerOptions(); 
                                
                                //affichage console
                                System.out.println( "Ceci est le premier demarrage de l'application, pensez a remplir la configuration !" );
                                //affichage fenetre
                                JOptionPane.showMessageDialog( frameComplete, "C'est la premiere fois que vous demarrez "+nomLog+".\nCommencez par verifier dans la configuration le chemin vers VLC !", "Bienvenue", JOptionPane.INFORMATION_MESSAGE);

                        }
                        catch( Exception e )
                        {

                        }
                }
                
                //import des programmations enregistrees
                importerProg();
                //Maj liste fichiers DOIT etre fait apres affichage
                majListeFic();
        }
        
/* creation de tous les panels */
        
        //Panel de commande de l'onglet 
        JPanel fairePanelDroite()
        {
                //Boutons de commande
                regarder = new JButton( "Regarder la chaine" );
                regarder.addActionListener( new ActionLireChaine() );
                
                enregistrer = new JButton( "Enregistrer la chaine" );
                enregistrer.addActionListener( new ActionEnrChaine() );
                
                programmer = new JButton( "Programmer un enregistrement");
                programmer.addActionListener( new ActionProgChaine() );
                
                //Mise en place du panel droite (boutons de commande)
                JPanel panelDroite = new JPanel();    
                panelDroite.setLayout( new GridLayout( 3, 1 ) );
                panelDroite.add( regarder );                          
                panelDroite.add( enregistrer );                 
                panelDroite.add( programmer );
                return panelDroite;
        }
        
        //Panel de la liste des chaines
        JPanel fairePanelGauche()
        {
                //Mise en place du panel gauche (liste des chaines)
                JPanel panelGauche = new JPanel();
                panelGauche.setLayout( new BorderLayout( 0, 0 ) );
                                
                listeAff = new javax.swing.JList();
                listeAff.setCellRenderer( new RenduListeChaines() );
                listeAff.setListData( listeChaines );
                listeAff.setSelectedIndex(0);
                listeAff.addMouseListener( new ActionDblClicChaine() );
                JScrollPane listeAvecAscenseur = new JScrollPane( listeAff );
                
                panelGauche.add( listeAvecAscenseur, BorderLayout.CENTER );
                return panelGauche;
        }
        
        //panel principal
        JPanel fairePanelPrincipal()
        {
                //Cr?ation panel gauche
                JPanel panelGauche = fairePanelGauche();
                
                //Cr?ation panel droite
                JPanel panelDroite = fairePanelDroite();
                
                //Panel principal : liste + boutons + en cours
                JPanel panelPrincipal = new JPanel();
                panelPrincipal.setLayout(new BorderLayout( 10, 10 ) );
                panelPrincipal.add(panelGauche, BorderLayout.CENTER);
                panelPrincipal.add(panelDroite, BorderLayout.EAST);
                labelEnCours = new JLabel( "En cours : " );
                panelPrincipal.add( labelEnCours, BorderLayout.SOUTH );
                return panelPrincipal;
        }
        
        //panel des enregsitrements
        JPanel fairePanelEnregistrements()
        {                
                //Panel d'enregistrements
                JPanel panelEnregistrements = new JPanel();
                panelEnregistrements.setLayout(new BorderLayout( 5, 5 ) );
                
                panelEnregistrements.add( new JLabel( "Enregistrements en cours :" ), BorderLayout.NORTH );
                                               
                listeAffEnr = new javax.swing.JList();                
                listeAffEnr.addListSelectionListener( new ActionSelListeEnr() );
                
                JScrollPane listeEnrAvecAscenseur = new JScrollPane( listeAffEnr );
                
                JPanel panelControle = new JPanel();
                
                arrEnr = new JButton( "Arreter" );
                arrEnr.addActionListener( new ActionArrEnr() );
                
                lireEnr = new JButton( "Lire" );
                lireEnr.addActionListener( new ActionLireEnr() );
                
                progFinEnr = new JButton( "Programmer la fin" );
                progFinEnr.addActionListener( new ActionProgFinEnr() );
                
                arrEnr.setEnabled( false );
                progFinEnr.setEnabled( false );
                lireEnr.setEnabled( false );
                
                panelControle.setLayout(new GridLayout( 1, 3, 3, 3 ) );
                panelControle.add( arrEnr );
                panelControle.add( lireEnr );
                panelControle.add( progFinEnr );
                
                panelEnregistrements.add( listeEnrAvecAscenseur, BorderLayout.CENTER );
                panelEnregistrements.add( panelControle, BorderLayout.SOUTH ); 
                return panelEnregistrements;
        }
        
        //panel des programmations
        JPanel fairePanelProgrammes()
        {                
                //Panel des programmations
                JPanel panelProgrammes = new JPanel();
                panelProgrammes.setLayout(new BorderLayout( 5, 5 ) );
                
                panelProgrammes.add( new JLabel( "Enregistrements programmes :" ), BorderLayout.NORTH );
                                               
                listeAffProg = new javax.swing.JList();
                listeAffProg.addListSelectionListener( new ActionSelListeProgrammes() );
                
                JScrollPane listeProgAvecAscenseur = new JScrollPane( listeAffProg );
                
                JPanel panelControle = new JPanel();
                
                nouvProg = new JButton( "Programmer un enregistrement" );
                nouvProg.addActionListener( new ActionNouvProg() );
                
                arretEnrProg = new JButton( "Arreter l'enregistrement" );
                arretEnrProg.addActionListener( new ActionArretEnrProg() );
                arretEnrProg.setEnabled( false );
                
                supprProg = new JButton( "Supprimer la programmation" );
                supprProg.addActionListener( new ActionSupprProg() );
                supprProg.setEnabled( false );
                                
                panelControle.setLayout(new GridLayout( 2, 1 , 3, 3 ) );
                JPanel panelLigne = new JPanel();
                panelLigne.setLayout(new GridLayout( 1, 2, 3, 3 ) );
                panelLigne.add( arretEnrProg );
                panelLigne.add( supprProg );
                panelControle.add( panelLigne );
                panelControle.add( nouvProg );
                
                panelProgrammes.add( listeProgAvecAscenseur, BorderLayout.CENTER );
                panelProgrammes.add( panelControle, BorderLayout.SOUTH ); 
                return panelProgrammes;
        }
        
        //panel des fichiers
        JPanel fairePanelFichiers()
        {                
                //Panel de gestion des fichiers
                JPanel panelFichiers = new JPanel();
                panelFichiers.setLayout(new BorderLayout( 5, 5 ) );
                
                panelFichiers.add( new JLabel( "Fichiers disponibles :" ), BorderLayout.NORTH );
                
                String[] labelsFicAff = new String[0];                                
                listeAffFic = new javax.swing.JList( labelsFicAff );
                
                
                JScrollPane listeFicAvecAscenseur = new JScrollPane( listeAffFic );
                
                JPanel panelControle = new JPanel();
                
                supprFic = new JButton( "Supprimer" );
                supprFic.addActionListener( new ActionSupprFic() );
                
                majListeFic = new JButton( "Actualiser" );
                majListeFic.addActionListener( new ActionMajListeFic() );
                
                lireFic = new JButton( "Lire" );
                lireFic.addActionListener( new ActionLireFic() );
                
                supprFic.setEnabled( false );
                lireFic.setEnabled( false );
                
                panelControle.setLayout(new GridLayout( 1, 3, 3, 3 ) );
                panelControle.add( lireFic );
                panelControle.add( supprFic );
                panelControle.add( majListeFic );
                
                panelFichiers.add( listeFicAvecAscenseur, BorderLayout.CENTER );
                panelFichiers.add( panelControle, BorderLayout.SOUTH ); 
                return panelFichiers;
        }
        
        //panel des options
        JPanel fairePanelOptions()
        {                
                //Panel d'options
                JPanel panelOptions = new JPanel();
                panelOptions.setLayout( new GridLayout( 7, 1, 3, 3 ) );
                
                //cr�ation des champs et boutons pour chemin vlc
                champChmVlc = new JTextField( chmVlc, 30 );
                choixFicVlc = new JButton( "..." );
                choixFicVlc.addActionListener( new ActionChoixFicVlc() );
                JPanel panelVlc = new JPanel();
                panelVlc.setLayout( new BorderLayout() );
                panelVlc.add( champChmVlc, BorderLayout.CENTER );
                panelVlc.add( choixFicVlc, BorderLayout.EAST );
                
                //cr�ation des champs et boutons pour chemin enregistrements
                champChmEnregistrements = new JTextField( chmEnregistrements, 30 );
                choixFicEnregistrements = new JButton( "..." );
                choixFicEnregistrements.addActionListener( new ActionChoixFicEnregistrements() );
                JPanel panelEnreg = new JPanel();
                panelEnreg.setLayout( new BorderLayout() );
                panelEnreg.add( champChmEnregistrements, BorderLayout.CENTER );
                panelEnreg.add( choixFicEnregistrements, BorderLayout.EAST );
                
                //bouton enregistrer options
                enrOptions = new JButton( "Enregistrer" );
                enrOptions.addActionListener( new ActionEnrOptions() );
                
                //bouton actualiser liste chaines
                majListeChaines = new JButton( "Actualiser la liste des chaines" );
                majListeChaines.addActionListener( new ActionImporterListeChaines() );
                
                //bouton maj programme
                majProg = new JButton( "Mettre a jour le programme" );
                majProg.addActionListener( new ActionMajProgramme() );
                                
                panelOptions.add( new JLabel( "Chemin complet vers VLC :" ) );
                panelOptions.add( panelVlc );
                panelOptions.add( new JLabel( "Dossier pour stocker les enregistrements :" ) );
                panelOptions.add( panelEnreg );
                panelOptions.add( enrOptions );
                panelOptions.add( majListeChaines );
                panelOptions.add( majProg );
                return panelOptions;
        }
        
/* Diff?rents rendus des listes */
        
        //rendu liste chaines
        class RenduListeChaines extends JLabel implements ListCellRenderer
        {            
                RenduListeChaines( )
                {
                        super();
                         setBorder( BorderFactory.createCompoundBorder(
                             BorderFactory.createMatteBorder( 0, 0, 1, 0, Color.lightGray ),
                             BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) ) );
                         setOpaque( true );
                }
                //construit un ?l?ment
                public Component getListCellRendererComponent(
                    JList liste,
                    Object valeur,
                    int index,
                    boolean isSelected,
                    boolean aFocus)
                {
                        
                        Chaine infos = (Chaine) valeur;
                        String nomChaine = infos.nom;
                        setText( nomChaine );
                        if( isSelected || aFocus )
                        {
                                setBackground( liste.getSelectionBackground() );
                                setForeground( liste.getSelectionForeground() );
                        }
                        else
                        {
                                setBackground( Color.white );
                                setForeground( Color.black );
                        }
                        return this;
                }
        }
        
        //rendu liste enregistrements
        class RenduListeEnr extends JTextArea implements ListCellRenderer
        {            
                RenduListeEnr( )
                {
                        super();
                         setBorder( BorderFactory.createCompoundBorder(
                             BorderFactory.createMatteBorder( 0, 0, 1, 0, Color.lightGray ),
                             BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) ) );
                        setColumns( (tailleFen.width - 30 ) / getColumnWidth() );
                }
                //construit un element
                public Component getListCellRendererComponent(
                    JList liste,
                    Object valeur,
                    int index,
                    boolean isSelected,
                    boolean aFocus)
                {
                        EnrEnCours infos = (EnrEnCours) valeur;
                        int idChaine = infos.indChaine;
                        
                        Date debut = infos.momentDep;
                        Calendar cal = Calendar.getInstance();
                        cal.setTime( debut );
                        
                        String nomChaine = ((Chaine) listeChaines.elementAt( idChaine )).nom;
                        String nomDebut = nbrDbl( cal.get( Calendar.DAY_OF_MONTH ) )+"/"+nbrDbl( cal.get( Calendar.MONTH ) )+"/"+ cal.get( Calendar.YEAR ) +" "+nbrDbl( cal.get( Calendar.HOUR_OF_DAY ) )+"h"+nbrDbl( cal.get( Calendar.MINUTE ) );
                                                
                        String programme = "";
                        if( infos.enrProgramme )
                                programme = "Programme par " + infos.getProgParent().nom + "\n";
                        
                        String chaineReprises = "";
                        if( infos.nbrReprises > 0 )
                                chaineReprises = "\n" + infos.nbrReprises + " reprise(s)";
                        
                        majBtnProg();
                        setText( "Chaine : " + nomChaine + "\nDebut : " + nomDebut + "\nFichier : " + infos.nomFichier + chaineReprises + "\n" + programme );
                        if( isSelected )
                        {
                                setBackground( liste.getSelectionBackground() );
                                setForeground( liste.getSelectionForeground() );
                        }
                        else
                        {
                                setBackground( Color.white );
                                setForeground( Color.black );
                        }
                        return this;
                }
        }
        
        
        //rendu liste fichiers
        class RenduListeFic extends JTextArea implements ListCellRenderer
        {            
                RenduListeFic( )
                {
                        super();
                         setBorder( BorderFactory.createCompoundBorder(
                             BorderFactory.createMatteBorder( 0, 0, 1, 0, Color.lightGray ),
                             BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) ) );
                        setColumns( (tailleFen.width - 30 ) / getColumnWidth() );
                }
                //construit un ?l?ment
                public Component getListCellRendererComponent(
                    JList liste,
                    Object valeur,
                    int index,
                    boolean isSelected,
                    boolean aFocus)
                {
                        
                        Fichier infos = (Fichier) valeur;
                        String nomFic = infos.nom;
                        int tailleFic = infos.taille;
                        setText( "Fichier : " + nomFic + "\nTaille : " + tailleFic + " Mo\n" );
                        if( isSelected )
                        {
                                setBackground( liste.getSelectionBackground() );
                                setForeground( liste.getSelectionForeground() );
                        }
                        else
                        {
                                setBackground( Color.white );
                                setForeground( Color.black );
                        }
                        return this;
                }
        }
        
        
        //rendu liste programmations
        class RenduListeProg extends JTextArea implements ListCellRenderer
        {            
                RenduListeProg( )
                {
                        super();
                        setColumns( (tailleFen.width - 30 ) / getColumnWidth() );
                         setBorder( BorderFactory.createCompoundBorder(
                             BorderFactory.createMatteBorder( 0, 0, 1, 0, Color.lightGray ),
                             BorderFactory.createEmptyBorder( 3, 3, 3, 3 ) ) );
                }
                //construit un element
                public Component getListCellRendererComponent(
                    JList liste,
                    Object valeur,
                    int index,
                    boolean isSelected,
                    boolean aFocus)
                {
                        
                        Programmation infos = (Programmation) valeur;
                        String nomProg = infos.nom;
                        String enCours;
                        if( infos.enCours )
                                enCours = "En cours d'enregistrement";
                        else
                                enCours = "En attente";
                        String date;
                        if( infos.estPonctuel )
                        {
                                date = "Le " + nbrDbl( infos.jour ) + "/" + nbrDbl( infos.mois ) + "/" + infos.annee;
                        }
                        else
                        {
                                date = "Tous les";
                                for( int k=0; k < infos.jours.size(); k++ )
                                {
                                        if( k == 0 )
                                                date+= " ";
                                        else
                                                date+= ", ";
                                        int jour = ((Integer) infos.jours.elementAt( k )).intValue();
                                        switch( jour )
                                        {
                                                case Calendar.MONDAY:
                                                        date+= "lundi";
                                                        break;
                                                case Calendar.TUESDAY:
                                                        date+= "mardi";
                                                        break;
                                                case Calendar.WEDNESDAY:
                                                        date+= "mercredi";
                                                        break;
                                                case Calendar.THURSDAY:
                                                        date+= "jeudi";
                                                        break;
                                                case Calendar.FRIDAY:
                                                        date+= "vendredi";
                                                        break;
                                                case Calendar.SATURDAY:
                                                        date+= "samedi";
                                                        break;
                                                case Calendar.SUNDAY:
                                                        date+= "dimanche";
                                                        break;
                                        }
                                }
                        }
                        setText( "Programmation : " + nomProg + "\n"
                            + date + "\n"
                            + "De " + nbrDbl( infos.heureDep ) + ":" + nbrDbl( infos.minuteDep ) + " a " + nbrDbl( infos.heureFin ) + ":" + nbrDbl( infos.minuteFin ) + "\n"
                            + enCours + "\n" );
                        if( isSelected )
                        {
                                setBackground( liste.getSelectionBackground() );
                                setForeground( liste.getSelectionForeground() );
                        }
                        else
                        {
                                setBackground( Color.white );
                                setForeground( Color.black );
                        }
                        return this;
                }
        }
        
/**************************************
 *Classes representant les actions
 *possibles depuis l'interface
 **************************************/

/* Actions de l'onglet principal */
        
        //action lecture/arret chaine s?lectionn?e
        class ActionLireChaine implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        if(! lectureEnCours.enCours )
                        {
                                //Lance la lecture d'une chaine
                                lectureEnCours.lancerChaine();
                        }
                        else
                        {
                                lectureEnCours.arreter();
                        }
                }
        }
        
        //action double clic sur la liste de chaines => lecture chaine s?lectionn?e
        class ActionDblClicChaine extends java.applet.Applet implements MouseListener
        {
                public void mouseClicked( MouseEvent event)
                {
                        if( event.getClickCount() == 2 )
                        {
                                //Lance la lecture d'une chaine
                                lectureEnCours.lancerChaine();
                        }
                }
                
                public void mouseEntered( MouseEvent e ){}
                public void mouseExited( MouseEvent e ){}                
                public void mousePressed( MouseEvent e ){}
                public void mouseReleased( MouseEvent e ){}
        }
        
        //action enregistrement immediat chaine s?lectionn?e
        class ActionEnrChaine implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        int indChaine;
                        indChaine = listeAff.getSelectedIndex();
                        String nomChaine = ((Chaine) listeChaines.elementAt( indChaine ) ).nom;
                        Calendar maintenant = Calendar.getInstance();
                        String nomFichier = simpChaine( nomChaine ) + "-" + maintenant.get( Calendar.DAY_OF_MONTH ) + "-" + maintenant.get( Calendar.MONTH ) + "-" + maintenant.get( Calendar.YEAR ) + "-" + maintenant.get( Calendar.HOUR_OF_DAY ) + "h" + maintenant.get( Calendar.MINUTE ) + extVideo;
                        enrEnCours.add( new EnrEnCours( indChaine, nomFichier ) );
                        //modif interface
                        majListeEnrEnCours();
                }
        }
        
        //action cr?ation nouveau programme pour la chaine s?lectionn?e
        class ActionProgChaine implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        FenetreProgrammation fenetre = new FenetreProgrammation();
                        fenetre.setChaineDep( listeAff.getSelectedIndex() );
                }
        }
        
/* Actions de l'onglet enregistrements */
        
        //action arret de l'enregistrement s?lectionn?
        class ActionArrEnr implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        int indEnr;
                        indEnr = listeAffEnr.getSelectedIndex();
                        //Suppression si non programme
                        if( ((EnrEnCours) enrEnCours.elementAt( indEnr )).progParent == null )
                                ((EnrEnCours) enrEnCours.elementAt( indEnr )).arreter();
                }
        }
        
        //action lecture de l'enregistrement en cours selectionne
        class ActionLireEnr implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        int indEnr;
                        indEnr = listeAffEnr.getSelectedIndex();
                        String nomFichier = ((EnrEnCours) enrEnCours.elementAt( indEnr )).nomFichier;

                        //Lance la lecture du fichier
                        lectureEnCours.lancerFichier( nomFichier );
                }
        }
        
        //action programmation de la fin d'un enregistrement
        class ActionProgFinEnr implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        int indEnr = listeAffEnr.getSelectedIndex();
                        FenetreProgrammation fenetre = new FenetreProgrammation();
                        fenetre.setEnr( (EnrEnCours) enrEnCours.elementAt( indEnr ) );
                }
        }
        
        //action changement selection liste enregistrements en cours (maj validite boutons)
        class ActionSelListeEnr implements ListSelectionListener
        {
                public void valueChanged(ListSelectionEvent event)
                {
                        //maj des boutons valides
                        majBtnEnr();
                }
        }
        
        //action verification du fonctionnement des enregistrements
        class ActionSurvEnr implements ActionListener
        {
                public void actionPerformed(ActionEvent evt)
                {
                        //parcours des enregistrements
                        for( int k=0; k < enrEnCours.size(); k++ )
                        {
                                EnrEnCours enr = (EnrEnCours) enrEnCours.elementAt(k);
                                if( enr.enCours )
                                {
                                        String nomFic = enr.nomFichier;
                                        if( enr.nbrReprises > 0 )
                                                nomFic = "reprise" + enr.nbrReprises + "_" + nomFic;
                                        File fic = new File( chmEnregistrements + sepDoss + nomFic );
                                        long tailleAct = fic.length();
                                        if( tailleAct == enr.ancTailleFic )
                                        {
                                            //on relance l'enregistrement
                                            enr.relancer();
                                            tailleAct = 0;
                                        }
                                        enr.ancTailleFic = tailleAct;
                                }
                        }
                        //on met en plus a jour la liste des fichiers
                        majListeFic();
                }
        }
        
/* Actions de l'onglet programmations */
        
        //action creation nouveau programme
        class ActionNouvProg implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        new FenetreProgrammation();
                }
        }
        
        //action arret d'un enregistrement d'une programmation
        class ActionArretEnrProg implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        int indProg;
                        indProg = listeAffProg.getSelectedIndex();
                        //Suppression
                        ((Programmation) listeProgrammes.elementAt( indProg )).arreterEnrEnCours();
                }
        }
        
        //action suppression d'une programmation
        class ActionSupprProg implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        int indProg;
                        indProg = listeAffProg.getSelectedIndex();                        
                        Programmation prog = (Programmation) listeProgrammes.elementAt( indProg );
                        if(! prog.fini )
                        {
                                prog.supprimer();
                                listeProgrammes.removeElementAt( indProg );
                        }
                        majListeProg();
                }
        }
        
        //action changement s?lection liste programmes (m?j validit? boutons)
        class ActionSelListeProgrammes implements ListSelectionListener
        {
                public void valueChanged(ListSelectionEvent event)
                {
                        //m?j des boutons valides
                        majBtnProg();
                }
        }
        
/* Actions de l'onglet fichiers */
        
        //action lecture d'un fichier
        class ActionLireFic implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        int indFic;
                        indFic = listeAffFic.getSelectedIndex();
                        String nomFichier = ((Fichier) listeFic.elementAt( indFic )).nom;

                        //Lance la lecture du fichier
                        lectureEnCours.lancerFichier( nomFichier );
                }
        }
        
        //action suppression d'un fichier
        class ActionSupprFic implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        int indFic;
                        indFic = listeAffFic.getSelectedIndex();
                        String nomFichier = ((Fichier) listeFic.elementAt( indFic )).nom;
                        int rep = JOptionPane.showConfirmDialog( frameComplete, "Supprimer le fichier "+nomFichier+" ?", "Suppression", JOptionPane.YES_NO_OPTION);
                        if( rep == JOptionPane.YES_OPTION )
                        {
                                try
                                {
                                        File fic = new File( chmEnregistrements + sepDoss + nomFichier );
                                        fic.delete();
                                        majListeFic();
                                }
                                catch( Exception e )
                                {
                                        System.out.println( "Impossible de supprimer le fichier : " + e.toString() );
                                        JOptionPane.showMessageDialog( frameComplete, "Impossible de supprimer le fichier.", "Erreur", JOptionPane.ERROR_MESSAGE);
                                }
                        }
                }
        }
        
        //action maj liste fichiers
        class ActionMajListeFic implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        majListeFic();
                }
        }
        
/* Actions de l'onglet options */
             
        //action enregistrement options
        class ActionEnrOptions implements ActionListener
        {
 
                public void actionPerformed(ActionEvent event)
                {
                        //Enregistre les options de l'onglet options
                        try
                        {
                                chmVlc = ( new File( champChmVlc.getText() ) ).getCanonicalPath();
                                File dossEnr = new File( champChmEnregistrements.getText() );
                                chmEnregistrements = dossEnr.getCanonicalPath();
                                if(! dossEnr.isDirectory() )
                                        dossEnr.mkdirs();
                                
                                //Enregistrement
                                enregistrerOptions();
                                majListeFic();
                                
                                JOptionPane.showMessageDialog( frameComplete, "Configuration enregistree", "Confirmation", JOptionPane.PLAIN_MESSAGE);
                                
                                onglets.setSelectedIndex( 0 );
                                
                        }
                        catch( Exception e )
                        {
                                System.out.println( "Erreur de prise en compte de la configuration : " + e );
                                JOptionPane.showMessageDialog( frameComplete, "La configuration n'a pas ete enregistree.", "Erreur", JOptionPane.ERROR_MESSAGE);
                        }
                }
        }
        
        //action importation liste des chaines
        class ActionImporterListeChaines implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        //m?j des boutons valides
                        importerListeChaines();
                }
        }
        
        //action choix du fichier pour VLC
        class ActionChoixFicVlc implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        JFileChooser choixFic = new JFileChooser();
                        int reponse = choixFic.showOpenDialog( frameComplete );
                        if(reponse == JFileChooser.APPROVE_OPTION )
                        {
                                try
                                {
                                        champChmVlc.setText( choixFic.getSelectedFile().getCanonicalPath() );
                                }
                                catch( Exception e )
                                {
                                        
                                }
                        }
                }
        }
        
        //action choix du dossier pour les enregistrements
        class ActionChoixFicEnregistrements implements ActionListener
        {
                public void actionPerformed(ActionEvent event)
                {
                        JFileChooser choixDoss = new JFileChooser();
                        choixDoss.setFileSelectionMode( JFileChooser.DIRECTORIES_ONLY );
                        int reponse = choixDoss.showOpenDialog( frameComplete );
                        if(reponse == JFileChooser.APPROVE_OPTION )
                        {
                                try
                                {
                                        champChmEnregistrements.setText( choixDoss.getSelectedFile().getCanonicalPath() );
                                }
                                catch( Exception e )
                                {
                                        
                                }
                        }
                }
        }
        
        //action maj du programme (si necessaire)
        class ActionMajProgramme implements ActionListener
        {
                public void actionPerformed( ActionEvent event )
                {
                        majProg.setText( "Mise a jour..." );
                        majProg.setEnabled( false );
                        int rep = majProgramme();
                        if( rep == -2 )
                                JOptionPane.showMessageDialog( frameComplete, "La verification de la version a echoue, merci de verifier manuellement sur le site de TvOnResel.", "Mise a jour", JOptionPane.ERROR_MESSAGE );
                        else if( rep == -1 )
                                JOptionPane.showMessageDialog( frameComplete, "Une nouvelle version est disponible mais elle ne peut etre mise a jour automatiquement, merci d'aller voir sur le site de TvOnResel.", "Mise a jour", JOptionPane.ERROR_MESSAGE );
                        else if( rep == 0 )
                                JOptionPane.showMessageDialog( frameComplete, "Votre version est a jour.", "Mise a jour", JOptionPane.INFORMATION_MESSAGE );
                        else if( rep == 1 )
                        {
                                
                                JOptionPane.showMessageDialog( frameComplete, "La mise a jour est terminee. Redemarrez le programme pour qu'elle prenne effet.", "Mise a jour", JOptionPane.INFORMATION_MESSAGE );
                        }
                        majProg.setText( "Mettre a jour le programme" );
                        majProg.setEnabled( true );
                }
        }
        
        
/*****************************************
 * Classe representant la fenetre
 * de choix pour les programmations
 ****************************************/
        
        //classe pour les choix pour les programmations
        class FenetreProgrammation extends JFrame
        {
                //champs ? remplir
                JTextField nom;
                JComboBox chaine;
                JTextField heureDep;
                JTextField heureFin;
                JTextField minuteDep;
                JTextField minuteFin;
                JTextField jour;
                JTextField mois;
                JTextField annee;
                JRadioButton btnDate;
                JRadioButton btnRep;
                JCheckBox lundi;
                JCheckBox mardi;
                JCheckBox mercredi;
                JCheckBox jeudi;
                JCheckBox vendredi;
                JCheckBox samedi;
                JCheckBox dimanche;
                
                //enregistrement ? inclure dans une programmation si n?cessaire
                EnrEnCours enrAProg = null;
                
                //construit la fen?tre
                public FenetreProgrammation()
                {
                        //Cr?ation de la fen?tre
                        super( nomLog + " - Programmer un enregistrement" );
                        
                        setLocationRelativeTo(null);
                        
                        //Evenement de fermeture
                        WindowListener fermeture = new WindowAdapter()
                        {
                                public void windowClosing(WindowEvent e)
                                {
                                        sortir();
                                }
                        };
                        addWindowListener( fermeture );
                        
                        //Ajout des composantes initialis?es
                        
                        Calendar aujourdhui = Calendar.getInstance();
                        
                        setLayout( new BorderLayout( 3, 3 ) );
                        JPanel panelIntitules = new JPanel();
                        JPanel panelValeurs = new JPanel();
                        JPanel panelControle = new JPanel();
                        add( new JLabel("Configurez votre programmation : " ), BorderLayout.NORTH );
                        add( panelIntitules, BorderLayout.WEST );
                        add( panelValeurs, BorderLayout.CENTER );
                        add( panelControle, BorderLayout.SOUTH );
                        
                        panelIntitules.setLayout( new GridLayout( 9, 1, 1, 1 ) );
                        panelValeurs.setLayout( new GridLayout( 9, 1, 1, 1 ) );
                        
                        panelIntitules.add( new JLabel( "Nom de la programmation : " ) );
                        nom = new JTextField( "prog" );
                        panelValeurs.add( nom );
                                               
                        panelIntitules.add( new JLabel( "Chaine a enregistrer : " ) );
                        String[] chaines = new String[listeChaines.size()];
                        for( int k=0 ; k < listeChaines.size() ; k++ )
                        {
                                chaines[k] = ( (Chaine) listeChaines.elementAt( k ) ).nom;
                        }
                        chaine = new JComboBox( chaines );
                        panelValeurs.add( chaine );
                        
                        panelIntitules.add( new JLabel( "Heure de debut : ") );
                        JPanel panelHeureDep = new JPanel();
                        heureDep = new JTextField( "" + aujourdhui.get( Calendar.HOUR_OF_DAY), 5 );
                        panelHeureDep.add( heureDep );
                        panelHeureDep.add( new JLabel( " : " ) );
                        minuteDep = new JTextField( "" + aujourdhui.get( Calendar.MINUTE ), 5 );
                        panelHeureDep.add( minuteDep );
                        panelValeurs.add( panelHeureDep );
                        
                        panelIntitules.add( new JLabel( "Heure de fin : ") );
                        JPanel panelHeureFin = new JPanel();
                        heureFin = new JTextField( "" + aujourdhui.get( Calendar.HOUR_OF_DAY), 5 );
                        panelHeureFin.add( heureFin );
                        panelHeureFin.add( new JLabel( " : " ) );
                        minuteFin = new JTextField( "" + aujourdhui.get( Calendar.MINUTE ), 5 );
                        panelHeureFin.add( minuteFin );
                        panelValeurs.add( panelHeureFin );
                        
                        panelIntitules.add( new JLabel( "Type de programmation : " ) );
                        ButtonGroup choixRep = new ButtonGroup();
                        btnDate = new JRadioButton( "Programmation ponctuelle le : ", true );
                        btnRep = new JRadioButton( "Repeter la programmation tous les : ", false );
                        choixRep.add( btnDate );
                        choixRep.add( btnRep );
                        
                        panelValeurs.add( btnDate );
                        
                        JPanel panelDate = new JPanel();
                        jour = new JTextField( "" + aujourdhui.get( Calendar.DAY_OF_MONTH ), 4 );
                        mois = new JTextField( "" + ( aujourdhui.get( Calendar.MONTH ) + 1 ), 4 );
                        annee = new JTextField( "" + aujourdhui.get( Calendar.YEAR ), 4 );
                        panelDate.add( jour );
                        panelDate.add( new JLabel( "/" ) );
                        panelDate.add( mois );
                        panelDate.add( new JLabel( "/" ) );
                        panelDate.add( annee );
                        panelValeurs.add( panelDate );
                        
                        panelValeurs.add( btnRep );
                        
                        JPanel ligne1 = new JPanel();
                        JPanel ligne2 = new JPanel();
                        
                        lundi = new JCheckBox( "lundi", aujourdhui.get( Calendar.DAY_OF_WEEK ) == Calendar.MONDAY );
                        mardi = new JCheckBox( "mardi", aujourdhui.get( Calendar.DAY_OF_WEEK ) == Calendar.TUESDAY );
                        mercredi = new JCheckBox( "mercredi", aujourdhui.get( Calendar.DAY_OF_WEEK ) == Calendar.WEDNESDAY );
                        jeudi = new JCheckBox( "jeudi", aujourdhui.get( Calendar.DAY_OF_WEEK ) == Calendar.THURSDAY );
                        vendredi = new JCheckBox( "vendredi", aujourdhui.get( Calendar.DAY_OF_WEEK ) == Calendar.FRIDAY );
                        samedi = new JCheckBox( "samedi", aujourdhui.get( Calendar.DAY_OF_WEEK ) == Calendar.SATURDAY );
                        dimanche = new JCheckBox( "dimanche", aujourdhui.get( Calendar.DAY_OF_WEEK ) == Calendar.SUNDAY );
                        
                        ligne1.add( lundi );
                        ligne1.add( mardi );
                        ligne1.add( mercredi );
                        ligne1.add( jeudi );
                        ligne2.add( vendredi );
                        ligne2.add( samedi );
                        ligne2.add( dimanche );
                        
                        panelValeurs.add( ligne1 );
                        panelValeurs.add( ligne2 );
                        
                        JButton valider = new JButton( "Valider" );
                        JButton annuler = new JButton( "Annuler" );
                        valider.addActionListener( new ActionValider() );
                        annuler.addActionListener( new ActionSortir() );
                        panelControle.setLayout( new GridLayout( 1, 2, 3, 3 ) );
                        panelControle.add( valider );
                        panelControle.add( annuler );
                        
                        //Affichage
                        pack();
                        setVisible( true );
                }
                
                //Choisir la chaine par d?faut (la chaine a donc ?t? choisie d'abord par l'utilisateur)
                public void setChaineDep( int indChaine )
                {
                        chaine.setSelectedIndex( indChaine );
                }
                
                //Choisir un enregistrement ? encadrer (l'utilisateur a cliqu? sur Programmer la fin de l'enregistrement)
                public void setEnr( EnrEnCours enr )
                {
                        enrAProg = enr;
                        Calendar momDep = Calendar.getInstance();
                        momDep.setTime( enr.momentDep );
                        heureDep.setText( "" + momDep.get( Calendar.HOUR_OF_DAY ));
                        heureDep.setEnabled( false );
                        minuteDep.setText( "" + momDep.get( Calendar.MINUTE ));
                        minuteDep.setEnabled( false );
                        chaine.setSelectedIndex( enr.indChaine );
                        chaine.setEnabled( false );
                        btnRep.setEnabled( false );
                        jour.setText( "" + momDep.get( Calendar.DAY_OF_MONTH ));
                        mois.setText( "" + ( momDep.get( Calendar.MONTH ) + 1 ) );
                        annee.setText( "" + momDep.get( Calendar.YEAR ) );
                        jour.setEnabled( false );
                        mois.setEnabled( false );
                        annee.setEnabled( false );
                        lundi.setEnabled( false );
                        mardi.setEnabled( false );
                        mercredi.setEnabled( false );
                        jeudi.setEnabled( false );
                        vendredi.setEnabled( false );
                        samedi.setEnabled( false );
                        dimanche.setEnabled( false );
                }
                
                //fermer la fen?tre
                void sortir()
                {
                        setVisible( false );
                }
                
                //message d'erreur
                void erreurFormat()
                {
                        JOptionPane.showMessageDialog( frameComplete, "Il y a une erreur dans votre programmation.", "Format incorrect", JOptionPane.ERROR_MESSAGE);
                }
        
                //action annulation
                class ActionSortir implements ActionListener
                {
                        public void actionPerformed(ActionEvent event)
                        {
                                sortir();
                        }
                }
        
                //action validation
                class ActionValider implements ActionListener
                {
                        public void actionPerformed(ActionEvent event)
                        {
                                try
                                {
                                        //V?rification du format des donn?es
                                        String nomC = simpChaine( nom.getText() );
                                        int heureDepC = Integer.parseInt( heureDep.getText() );
                                        int minuteDepC = Integer.parseInt( minuteDep.getText() );
                                        int heureFinC = Integer.parseInt( heureFin.getText() );
                                        int minuteFinC = Integer.parseInt( minuteFin.getText() );
                                        int chaineC = chaine.getSelectedIndex();
                                        
                                        //format des heures et minutes
                                        if( heureDepC > 23 || heureFinC > 23 || minuteDepC > 59 || minuteFinC > 59 || heureDepC < 0 || heureFinC < 0 || minuteDepC < 0 || minuteFinC < 0 )
                                        {
                                                erreurFormat();
                                        }
                                        else
                                        {
                                                boolean estPonctuel = btnDate.isSelected();
                                                if( estPonctuel )
                                                {
                                                        //enregistrement ponctuel
                                                        int jourC = Integer.parseInt( jour.getText() );
                                                        int moisC = Integer.parseInt( mois.getText() );
                                                        int anneeC = Integer.parseInt( annee.getText() );
                                                        
                                                        //le mois
                                                        if( moisC > 12 || moisC < 1 )
                                                        {
                                                                erreurFormat();
                                                        }
                                                        else
                                                        {
                                                                Calendar dateDem = Calendar.getInstance();
                                                                dateDem.set( Calendar.YEAR, anneeC );
                                                                dateDem.set( Calendar.MONTH, moisC );
                                                                //le jour
                                                                if( jourC > dateDem.getActualMaximum( Calendar.DATE ) || jourC < 0 )
                                                                {
                                                                        erreurFormat();
                                                                }
                                                                else
                                                                {
                                                                        if( enrAProg == null )
                                                                        {
                                                                                //on cr?e une programmation de toutes pi?ces
                                                                                listeProgrammes.add( new Programmation( nomC, chaineC, jourC, moisC - 1, anneeC, heureDepC, minuteDepC, heureFinC, minuteFinC ) );
                                                                                majListeProg();    
                                                                                sortir();
                                                                        }
                                                                        else
                                                                        {
                                                                                //on inclut un enregistrement dans une programmation
                                                                                listeProgrammes.add( new Programmation( nomC, enrAProg, heureFinC, minuteFinC ) );
                                                                                majListeProg();
                                                                                sortir();
                                                                        }
                                                                }
                                                        }
                                                }
                                                else
                                                {
                                                        //Programmation chaque semaine
                                                        Vector jours = new Vector();
                                                        if( lundi.isSelected() ) jours.add( new Integer( Calendar.MONDAY ) );
                                                        if( mardi.isSelected() ) jours.add( new Integer( Calendar.TUESDAY ) );
                                                        if( mercredi.isSelected() ) jours.add( new Integer( Calendar.WEDNESDAY ) );
                                                        if( jeudi.isSelected() ) jours.add( new Integer( Calendar.THURSDAY ) );
                                                        if( vendredi.isSelected() ) jours.add( new Integer( Calendar.FRIDAY ) );
                                                        if( samedi.isSelected() ) jours.add( new Integer( Calendar.SATURDAY ) );
                                                        if( dimanche.isSelected() ) jours.add( new Integer( Calendar.SUNDAY ) );
                                                        listeProgrammes.add( new Programmation( nomC, chaineC, jours, heureDepC, minuteDepC, heureFinC, minuteFinC ) );
                                                        majListeProg();
                                                        sortir();
                                                }
                                        }
                                }
                                catch( Exception e )
                                {
                                       System.out.println( e.toString() );
                                        erreurFormat();
                                }
                        }
                }
        }
 
/*********************************
 * Fonctions diverses
 *********************************/
        
/* Fonctions souvent utiles */
        
        //Sortie du programme : ferme tout        
        public boolean sortir()
        {
                int rep = JOptionPane.YES_OPTION;
                /*
                if( lectureEnCours.enCours || enrEnCours.size() > 0 )
                {
                        rep = JOptionPane.showConfirmDialog( frameComplete, "Fermer " + nomLog + " ?\nLes enregistrements et lectures en cours seront arr?t?s.", "Au revoir", JOptionPane.YES_NO_OPTION);
                }
                 */
                if( rep == JOptionPane.YES_OPTION )
                {
                    lectureEnCours.arreter();

                    //Enregistrement des programmes
                    enregistrerProg();

                    //Arret des programmes !
                    //? faire avant l'arret des enregistrements !
                    for( int k=0; k < listeProgrammes.size(); k++ )
                    {
                            Programmation prog = (Programmation) listeProgrammes.elementAt(k);
                            if( prog.enCours )
                            {
                                    prog.arreterEnrEnCours();
                                    k--; //maj integree enleve l'element de la liste
                            }
                    }

                    //arret des enregistrements
                    for( int k=0; k < enrEnCours.size(); k++ )
                    {
                            EnrEnCours enr = (EnrEnCours) enrEnCours.elementAt(k);
                            enr.arreter();
                            k--; //maj integree enleve l'element de la liste
                    }

                    //fin
                    System.exit(0);
                    return true;
                }
                else
                {
                    return false;
                }
        }
        
        //maj automatique du programme
        int majProgramme( )
        {
                //recuperation des infos de version
                /* retourne :
                 * -2 : erreur dans la recuperation
                 * -1 : nouvelle version mais pas de maj auto
                 * 0 : pas de maj
                 * 1 : maj faite
                 */
                String contenu = "";
                try
                {
                        //lecture a l'url
                        URL ficD = new URL( urlInfosMaj );
                        InputStream flux =  ficD.openStream();
                        for( int carLu = flux.read(); carLu != -1; carLu = flux.read() )
                        {
                                contenu += (char) carLu;
                        }
                        flux.close();
                }
                catch( Exception e )
                {
                        System.out.println( "Erreur lecture informations de version : " + e );
                        return -2;
                }
                        
                //possibilite de specifier une nouvelle adressepour les infos maj (REDIRECTION:http://...)
                Pattern masqueRedir = Pattern.compile( "REDIRECTION\\s*:\\s*(\\S+)" );
                Matcher trouveurRedir = masqueRedir.matcher( contenu );
                if( trouveurRedir.find() )
                {
                        String nouvUrl = trouveurRedir.group( 1 );
                        try
                        {
                                URL testURL = new URL( nouvUrl );
                                urlInfosMaj = nouvUrl;
                                enregistrerOptions();
                                return majProgramme();
                        }
                        catch( Exception e )
                        {
                                System.out.println( "Erreur redirection informations de version : " + e );
                                return -2;
                        }
                }
                else
                { 
                        //le fichier est bien la, on verifie son format
                        Pattern masqueInfos = Pattern.compile( "version\\s*:\\s*([0-9]+\\.[0-9]+[a-z]?)\\s*(fichier\\s*:\\s*(\\S+\\.jar))?", Pattern.DOTALL + Pattern.MULTILINE );
                        Matcher trouveurInfos = masqueInfos.matcher( contenu );
                        if(! trouveurInfos.find() )
                        {
                                System.out.println( "Erreur format informations de version" );
                                return -2;
                        }
                        String numVersion = trouveurInfos.group( 1 );
                        String urlNouv = trouveurInfos.group( 3 );
                        //version non modifiee ?
                        if( numVersion.equals( versionLog ) )
                                return 0;
                        //pas de fichier de maj ?
                        if( urlNouv == null )
                                return -1;
                        try
                        {
                                //lecture a l'url du fichier de maj et copie dans le fichier local
                                //ouverture fichier local
                                Pattern masqueJar = Pattern.compile( ".jar$" );
                                Matcher trouveurJar = masqueJar.matcher( chmFicExec );
                                if(! trouveurJar.find() )
                                        return -1;
                                
                                File ficJar = new File( chmFicExec );                                
                                if(! ficJar.isFile() )
                                        return -1;
                                
                                //ouverture fichier distant
                                URL nouvFicDist = new URL( urlNouv );
                                InputStream nouvFlux =  nouvFicDist.openStream();
                                FileOutputStream cible = new FileOutputStream( ficJar );
                                // Lecture par segment de 0.5Mo 
                                byte[] buffer = new byte[512*1024];
                                int nbLecture;
                                while( (nbLecture = nouvFlux.read(buffer)) != -1 ) {
                                        cible.write( buffer, 0, nbLecture);
                                }
                                nouvFlux.close();
                                cible.close(); 
                                return 1;
                        }
                        catch( Exception e )
                        {
                                System.out.println( "Erreur lecture/ecriture nouvelle version : " + e );
                                return -1;
                        }
                }
        }
        
        //simplification d'une chaine pour en faire un nom de fichier
        String simpChaine( String chaine )
        {
                char car;
                String resultat = "";
                for (int i = 0 ; i < chaine.length() ;i++)
                {
                        car = chaine.charAt( i );
                        if( ( car >= 'a' && car <= 'z' ) || ( car >= 'A' && car <= 'Z' ) || ( car >= '0' && car <= '9' ) )
                                resultat+=car;
                }
                return resultat;
        }
        
        //Rajoute un 0 a gauche des nombres si n?cessaire pour obtenir deux chiffres : 1 -> 01
        String nbrDbl( int nbr )
        {
                if( nbr < 10 )
                        return "0" + nbr;
                else
                        return "" + nbr;
        }
        
/* Fonctions agissant sur la liste des chaines */
       
        //lecture du fichier local de liste des chaines, enregistrement du vecteur qui les repr?sente
        void lireListeChaines()
        {
                //Lecture du fichier liste des chaines
                int lu;
                char carLu;
                String ligne;
                String nomChaine = "";
                String adresseChaine = "";
                listeChaines.clear();
                try
                {
                        FileReader liste = new FileReader( dossierExec + sepDoss + nomFicChaines );
                        //lecture par caract?re
                        lu = liste.read();
                        while( lu != -1 )
                        {
                                carLu = (char) lu;
                                ligne = "";
                                while( carLu != '\n' && lu != -1 )
                                {
                                        ligne+= carLu;
                                        lu = liste.read();
                                        if( lu != -1 )
                                                carLu = (char) lu;
                                }
                                //on a toute une ligne
                                if( nomChaine == "" )
                                {
                                        Pattern masque = Pattern.compile( "^\\s*#EXTINF\\s*:\\s*0\\s*,\\s*(.+?)\\s*$" );
                                        Matcher trouveur = masque.matcher( ligne );
                                        
                                        if( trouveur.find() )
                                        {
                                                //on trouve un nom de chaine
                                                nomChaine = trouveur.group( 1 );
                                        }
                                }
                                else
                                {
                                        //on a toutes les infos sur la chaine : on ajoute
                                        Pattern masque2 = Pattern.compile( "^\\s*(.*?)\\s*$" );
                                        Matcher trouveur2 = masque2.matcher( ligne );
                                        trouveur2.find();
                                        
                                        adresseChaine = trouveur2.group( 1 );
                                        listeChaines.addElement( new Chaine( adresseChaine, nomChaine ) );
                                        nomChaine = "";
                                }
                                lu = liste.read();
                        }
                }
                catch( Exception e )
                {
                        //le fichier n'existe pas, on essaye de le r�cup�rer sur internet
                        //on cr�e d'abord un fichier vide pour ne pas boucler
                        //entre importerListeChaines et lireListeChaines
                        //Ecriture dans le fichier local de liste des chaines
                        try
                        {       
                                 FileWriter cible = new FileWriter( nomFicChaines );
                                 cible.write( "" );
                                 cible.close();
                                importerListeChaines();                                 
                        }
                        catch( Exception f )
                        {
                                System.out.println( "Impossible de recuperer la liste des chaines : " + f );
                        }
                }
        }
        
        //Recupere la liste de chaines dans un fichier distant
        //url dans la config
        //copie cette liste dans le fichier local et maj
        void importerListeChaines()
        {
                //recuperation du fichier complet
                String contenu = "";
                try
                {
                        //lecture a l'url
                        URL ficDist = new URL( urlListeChaines );
                        InputStream flux =  ficDist.openStream();
                        for( int carLu = flux.read(); carLu != -1; carLu = flux.read() )
                        {
                                contenu += (char) carLu;
                        }
                        flux.close();
                }
                catch( Exception e )
                {
                        System.out.println( "Impossible d'acceder ? la liste des chaines distante : " + e );
                }
                        
                //possibilite de specifier une nouvelle adresse (REDIRECTION:http://...)
                Pattern masqueRedir = Pattern.compile( "REDIRECTION\\s*:\\s*(\\S+)" );
                Matcher trouveurRedir = masqueRedir.matcher( contenu );
                if( trouveurRedir.find() )
                {
                        String nouvUrl = trouveurRedir.group( 1 );
                        try
                        {
                                URL testURL = new URL( nouvUrl );
                                urlListeChaines = nouvUrl;
                                enregistrerOptions();
                                importerListeChaines();
                        }
                        catch( Exception e )
                        {
                                
                        }
                }
                else
                {
                        //Ecriture dans le fichier local de liste des chaines
                        try
                        {       
                                 FileWriter cible = new FileWriter( dossierExec + sepDoss + nomFicChaines );
                                 cible.write( contenu );
                                 cible.close();
                                 //on affiche les nouvelles chaines
                                 lireListeChaines();
                                 
                        }
                        catch( Exception e )
                        {
                                System.out.println( "Erreur d'ecriture du fichier de liste des chaines : " + e );
                        }
                }
        }
        
/* Fonctions agissant sur les enregistrements en cours */
        
        //met a jour l'interface pour la liste des enregistrements en cours
        void majListeEnrEnCours( )
        {
                //m?j enrEnCours : suppression enregistrements termines
                for( int k=0; k < enrEnCours.size(); k++ )
                {
                        EnrEnCours element = (EnrEnCours) enrEnCours.elementAt( k );
                        if(! element.enCours )
                                enrEnCours.removeElementAt( k );
                }
                //Cr?ation si necessaire
                if(! listeAffEnrOk )
                {
                        listeAffEnr.setCellRenderer( new RenduListeEnr( ) );
                        listeAffEnrOk = true;
                }
                
                listeAffEnr.setListData( enrEnCours );
                //gestion de la validite des boutons
                if( enrEnCours.size() > 0 )
                {
                        listeAffEnr.setSelectedIndex(0);
                        majBtnEnr();
                        lireEnr.setEnabled( true );
                }
                else
                {
                        lireEnr.setEnabled( false );
                }                     
                //maj de la surveillance des enregistrements
                majSurvEnr();
                //met a jour la liste des fichiers en m?me temps
                majListeFic();
        }
        
        //maj de la validite des boutons de l'onglet enregistrement
        //selon l'enregistrement selectionne
        void majBtnEnr()
        {
                int indEnr;
                indEnr = listeAffEnr.getSelectedIndex();
                if( indEnr >= 0 )
                {
                        EnrEnCours enr = (EnrEnCours) enrEnCours.elementAt( indEnr );
                        if( enr.enrProgramme )
                        {
                                arrEnr.setEnabled( false );
                                progFinEnr.setEnabled( false );
                        }
                        else
                        {
                                arrEnr.setEnabled( true );
                                progFinEnr.setEnabled( true );
                        }
                }
                else
                {
                        arrEnr.setEnabled( false );
                        lireEnr.setEnabled( false );
                        progFinEnr.setEnabled( false );                        
                }
        }
        
        //maj du timer de surveillance des enregistrements
        void majSurvEnr()
        {       
                //initialisatio
                if( timerSurvEnr == null )
                        timerSurvEnr = new javax.swing.Timer( tempsInterVerif * 1000, new ActionSurvEnr() );
                //verification
                if( enrEnCours.size() > 0 )
                {
                        if(! timerSurvEnr.isRunning() )
                                timerSurvEnr.start();
                }
                else
                {
                        if( timerSurvEnr.isRunning() )
                                timerSurvEnr.stop();
                }
        }
        
/* Fonctions agissant sur les programmations */
        
        //met a jour l'interface pour la liste des programmations en cours
        void majListeProg()
        {
                //suppression des programmations termin?es
                for( int k=0; k < listeProgrammes.size(); k++ )
                {
                        Programmation element = (Programmation) listeProgrammes.elementAt( k );
                        if( element.fini )
                        {
                                listeProgrammes.removeElementAt( k );
                                k--;
                        }
                }
                //Cr?ation si n?cessaire de la liste affich?e
                if(! listeAffProgOk )
                {
                        listeAffProg.setCellRenderer( new RenduListeProg( ) );
                        listeAffProgOk = true;
                }
                                
                listeAffProg.setListData( listeProgrammes );
                
                //gestion de la validit? des boutons
                if( listeProgrammes.size() > 0 )
                {
                        listeAffProg.setSelectedIndex( 0 );
                        majBtnProg();
                }
                else
                {
                        arretEnrProg.setEnabled( false );
                        supprProg.setEnabled( false );
                }
                majListeFic();
        }
        
        //g?re la validit? des boutons de l'onglet programmations
        //en fonction de la programmation s?lectionn?e
        void majBtnProg()
        {
                //modification des boutons valides
                int indProg;
                indProg = listeAffProg.getSelectedIndex();
                if( indProg >= 0 )
                {
                        Programmation prog = (Programmation) listeProgrammes.elementAt( indProg );
                        if( prog.enCours )
                        {
                                arretEnrProg.setEnabled( true );
                                supprProg.setEnabled( false );
                        }
                        else
                        {
                                arretEnrProg.setEnabled( false );
                                supprProg.setEnabled( true );
                        }
                }
                else
                {
                        arretEnrProg.setEnabled( false );
                        supprProg.setEnabled( false );
                }
        }
        
        //Enregistre les programmations en cours dans un fichier
        void enregistrerProg()
        {
                //Cr?ation de la chaine
                //on utilise la fonction bijective repTexte des objets Programmation
                String chaine = "";
                for( int k=0; k < listeProgrammes.size(); k++ )
                {
                        Programmation prog = (Programmation) listeProgrammes.elementAt( k );
                        chaine += "\n\n" + prog.repTexte();
                }
                
                //Ecriture dans le fichier
                try
                {       
                         FileWriter cible = new FileWriter( dossierExec + sepDoss + nomFicProgrammations );
                         cible.write( chaine );
                         cible.close();
                }
                catch( Exception e )
                {
                        System.out.println( "Erreur d'ecriture du fichier des programmations : " + e );
                }
        }
        
        //Recupere les programmations dans un fichier, et les reactive en tant qu'objets Programmation
        void importerProg()
        {
                int lu;
                char carLu;
                String chaine = "";
                
                try
                {
                        FileReader liste = new FileReader( dossierExec + sepDoss + nomFicProgrammations );
                        //lecture par caractere
                        lu = liste.read();
                        while( lu != -1 )
                        {
                                carLu = (char) lu;
                                chaine+= carLu;
                                lu = liste.read();
                        }
                        //on a tout le fichier dans chaine
                        Pattern masqueProg = Pattern.compile( "<programmation>.*?</programmation>", Pattern.DOTALL );
                        Matcher trouveurProg = masqueProg.matcher( chaine );
                        //on parcourt chaque programmation
                        //on recree les programmations grace a la methode progDeTexte
                        while( trouveurProg.find() )
                        {
                                Programmation prog = (new Programmation()).progDeTexte( trouveurProg.group( 0 ) );
                                if( prog != null && (! prog.fini) )
                                {
                                        listeProgrammes.add( prog );
                                }
                        }
                        //on met a jour la liste (interface)
                        majListeProg();
                        
                }
                catch( Exception e )
                {
                        //pas de fichier, on importe rien
                        majListeProg();
                }
                
        }
        
/* Fonctions agissant sur la liste des fichiers */
        
        //met a jour l'interface pour la liste des fichiers
        void majListeFic( )
        {
                //Cr?ation si n?cessaire de la liste affich?e                
                if(! listeAffFicOk )
                {
                        listeAffFic.setCellRenderer( new RenduListeFic( ) );
                        listeAffFicOk = true;
                }
                
                //Parcours du dossier
                File doss = new File( chmEnregistrements );
                String [] listeTemp = doss.list();
                
                if( listeTemp != null )
                {
                        //Remise ? 0 liste
                        listeFic = new Vector();
                        for( int i =0; i < listeTemp.length; i++)
                        {
                                File ficAct = new File( chmEnregistrements + sepDoss + listeTemp[i] );
                                if(! new File( chmEnregistrements + sepDoss + listeTemp[i] ).isDirectory() )
                                {
                                        listeFic.add( new Fichier( listeTemp[i], ( new Long( ficAct.length() / ( 1000 * 1000) ) ).intValue() ) );
                                }
                        }
                        listeAffFic.setListData( listeFic );
                }

                //gestion de la validit? des boutons
                if( listeFic.size() > 0 )
                {
                        supprFic.setEnabled( true );
                        lireFic.setEnabled( true );
                        listeAffFic.setSelectedIndex(0);
                }
                else
                {
                        supprFic.setEnabled( false );
                        lireFic.setEnabled( false );
                }
                        
        }
        
/* Fonctions agissant sur les options */
        
        //lecture des options dans le fichier local config.txt
        void lireOptions()
        {
                //Lecture du fichier par ligne
                int lu;
                char carLu;
                String ligne;
                
                try
                {
                        FileReader liste = new FileReader( dossierExec + sepDoss + nomFicOptions );
                        //lecture par caractere
                        lu = liste.read();
                        while( lu != -1 )
                        {
                                carLu = (char) lu;
                                ligne = "";
                                while( carLu != '\n' && lu != -1 )
                                {
                                        ligne+= carLu;
                                        lu = liste.read();
                                        if( lu != -1 )
                                                carLu = (char) lu;
                                }
                                //on a toute une ligne

                                Pattern masque = Pattern.compile( "^ *([a-zA-Z_-]+) *= *([^#]*) *(#.*)?$" );
                                Matcher trouveur = masque.matcher( ligne );
                                if( trouveur.find() )
                                {
                                        //si variable connue, on la charge
                                        String nomVar = trouveur.group( 1 );
                                        String contVar = trouveur.group( 2 );
                                        if( nomVar.equals(  "nomFicChaines" ) )
                                                nomFicChaines = contVar;
                                        else if( nomVar.equals( "chmVlc" ) )
                                                chmVlc = contVar;
                                        else if( nomVar.equals( "chmEnregistrements" ) )
                                                chmEnregistrements = contVar;
                                        else if( nomVar.equals( "urlListeChaines" ) )
                                                urlListeChaines = contVar;
                                        else if( nomVar.equals( "urlInfosMaj" ) )
                                                urlInfosMaj = contVar;
                                        else if( nomVar.equals( "tempsInterVerif" ) )
                                                tempsInterVerif = Integer.parseInt( contVar );
                                        else if( nomVar.equals( "premierDemarrage" ) )
                                                premierDemarrage = (contVar.equals( "1" ) );
                                        else
                                                System.out.println( "Variable de configuration inconnue : "+nomVar );
                                }
                                //on continue
                                lu = liste.read();
                        }
                }
                catch( Exception e )
                {
                        //pas de fichier de config
                        //on enregistre la config actuelle
                        //(permet de creer le fichier)
                        enregistrerOptions();
                }
        }
        
        //Enregistre dans le fichier de configuration les options actuelles
        void enregistrerOptions()
        {
                //Lecture du fichier d'options
                int lu;
                char carLu;
                String ligne;
                String chaineAEnregistrer = "";
                //Variables a enregistrer obligatoirement
                boolean nomFicChainesOk = false;
                boolean chmVlcOk = false;
                boolean chmEnregistrementsOk = false;
                boolean urlListeChainesOk = false;
                boolean urlInfosMajOk = false;
                boolean premierDemarrageOk = false;
                boolean tempsInterVerifOk = false;
                
                
                try
                {
                        //on lit d'abord le fichier pour conserver sa structure
                        FileReader liste = new FileReader( dossierExec + sepDoss + nomFicOptions );
                        //lecture par caractere
                        lu = liste.read();
                        while( lu != -1 )
                        {
                                carLu = (char) lu;
                                ligne = "";
                                while( carLu != '\n' && lu != -1 )
                                {
                                        ligne+= carLu;
                                        lu = liste.read();
                                        if( lu != -1 )
                                                carLu = (char) lu;
                                }
                                //on a toute une ligne

                                Pattern masque = Pattern.compile( "^ *([a-zA-Z_-]+) *= *([^#]*)( *(#.*)?)$" );
                                Matcher trouveur = masque.matcher( ligne );
                                if( trouveur.find() )
                                {
                                        //si on reconnait la ligne, on maj la valeur de la variable
                                        //sinon on laisse la ligne
                                        String nomVar = trouveur.group( 1 );
                                        String contVar = trouveur.group( 2 );
                                        String commentaires = trouveur.group( 3 );
                                        if( nomVar.equals(  "nomFicChaines" ) )
                                        {
                                                chaineAEnregistrer+= "nomFicChaines = "+nomFicChaines;
                                                nomFicChainesOk = true;
                                        }
                                        else if( nomVar.equals( "chmVlc" ) )
                                        {
                                                chaineAEnregistrer+= "chmVlc = "+chmVlc;
                                                chmVlcOk = true;
                                        }
                                        else if( nomVar.equals( "chmEnregistrements" ) )
                                        {
                                                chaineAEnregistrer+= "chmEnregistrements = "+chmEnregistrements;
                                                chmEnregistrementsOk = true;
                                        }
                                        else if( nomVar.equals( "urlListeChaines" ) )
                                        {
                                                chaineAEnregistrer+= "urlListeChaines = "+urlListeChaines;
                                                urlListeChainesOk = true;
                                        }
                                        else if( nomVar.equals( "urlInfosMaj" ) )
                                        {
                                                chaineAEnregistrer+= "urlInfosMaj = "+urlInfosMaj;
                                                urlInfosMajOk = true;
                                        }
                                        else if( nomVar.equals( "tempsInterVerif" ) )
                                        {
                                                chaineAEnregistrer+= "tempsInterVerif = "+tempsInterVerif;
                                                tempsInterVerifOk = true;
                                        }
                                        else if( nomVar.equals( "premierDemarrage" ) )
                                        {
                                                if( premierDemarrage )
                                                        chaineAEnregistrer+= "premierDemarrage = 1";
                                                else
                                                        chaineAEnregistrer+= "premierDemarrage = 0";
                                                        
                                                premierDemarrageOk = true;
                                        }
                                        else
                                                chaineAEnregistrer+= nomVar+" = "+contVar;
                                        chaineAEnregistrer+= commentaires;
                                }
                                else
                                {
                                        chaineAEnregistrer+= ligne;
                                }
                                chaineAEnregistrer+= "\n";
                                //on continue
                                lu = liste.read();
                        }
                }
                catch( Exception e )
                {
                        //on n'a pas de fichier de config, on le cree
                }
                finally
                {
                        

                        //ajout des variables non trouvees dans le fichier de config
                        //on les ajoute a la fin
                        if(! nomFicChainesOk )
                                chaineAEnregistrer+= "\nnomFicChaines = "+nomFicChaines;
                        if(! chmVlcOk )
                                chaineAEnregistrer+= "\nchmVlc = "+chmVlc;
                        if(! chmEnregistrementsOk )
                                chaineAEnregistrer+= "\nchmEnregistrements = "+chmEnregistrements;
                        if(! urlListeChainesOk )
                                chaineAEnregistrer+= "\nurlListeChaines = "+urlListeChaines;
                        if(! urlInfosMajOk )
                                chaineAEnregistrer+= "\nurlInfosMaj = "+urlInfosMaj;
                        if(! tempsInterVerifOk )
                                chaineAEnregistrer+= "\ntempsInterVerif = "+tempsInterVerif;
                        if(! premierDemarrageOk )
                                if( premierDemarrage )
                                        chaineAEnregistrer+= "\npremierDemarrage = 1";
                                else
                                        chaineAEnregistrer+= "\npremierDemarrage = 0";
                
                        //Ecriture du nouveau fichier
                        try
                        {       
                                 FileWriter cible = new FileWriter( dossierExec + sepDoss + nomFicOptions );
                                 cible.write( chaineAEnregistrer );
                                 cible.close();
                        }
                        catch( Exception e )
                        {
                                System.out.println( "Erreur d'ecriture du fichier de configuration : " + e );
                        }
                }
                
        }
        
/***********************************
 * Classes pour decrire les objets
 * manipules dans ce programme
 **********************************/
        
/* Classes simples de description */
        
        //Decrit une chaine
        class Chaine
        {
                public String adresse;
                public String nom;
                Chaine( String adr, String nomChaine )
                {
                        adresse = adr;
                        nom = nomChaine;
                }
        }
        
        //Decrit un fichier
        class Fichier
        {
                public int taille;
                public String nom;
                Fichier( String nomF, int tailleF )
                {
                        taille = tailleF;
                        nom = nomF;
                }
        }
        
        //Decrit un parametre a passer a vlc (d�pend du syst�me)
        class ParametreVlc
        {
                String nom;
                String valeur;
                String precisions;
                String paramSeul = "";
                int pourOS = 0;
                static final int TOUS_SYSTEMES = 0;
                static final int UNIX = 1;
                static final int WINDOWS = 2;
                
                //vrai parametre avec precisions pour tous OS
                ParametreVlc( String n, String v, String p )
                {
                        nom = n;
                        valeur = v;
                        precisions = p;
                }
                
                //vrai parametre sans precisions pour tous OS
                ParametreVlc( String n, String v )
                {
                        nom = n;
                        valeur = v;
                        precisions = "";
                }
                
                //faux parametre : fichier... pour tous OS
                ParametreVlc( String p )
                {
                        paramSeul = p;
                }
                
                //vrai parametre avec precisions pour OS specifie
                ParametreVlc( String n, String v, String p, int pour )
                {
                        nom = n;
                        valeur = v;
                        precisions = p;
                        pourOS = pour;
                }
                
                //vrai parametre sans precisions pour OS specifie
                ParametreVlc( String n, String v, int pour )
                {
                        nom = n;
                        valeur = v;
                        precisions = "";
                        pourOS = pour;
                }
                
                //faux parametre : fichier... pour OS specifie
                ParametreVlc( String p, int pour )
                {
                        paramSeul = p;
                        pourOS = pour;
                }
                
                //renvoie la chaine du param�tre selon l'OS
                String chaine()
                {
                        String systeme = System.getProperty( "os.name" );
                        Pattern masqueWin = Pattern.compile( "windows" );
                        Matcher trouveurWin = masqueWin.matcher( systeme.toLowerCase() );
                        if( trouveurWin.find() )
                        {
                                if( pourOS == TOUS_SYSTEMES || pourOS == WINDOWS )
                                {
                                        if(! paramSeul.equals( "" ) )
                                                return paramSeul;
                                        else
                                                return "--" + nom + "=\"" + valeur + "\"" + precisions;
                                }
                        }
                        else
                        {
                                if( pourOS == TOUS_SYSTEMES || pourOS == UNIX )
                                {
                                        if(! paramSeul.equals( "" ) )
                                                return paramSeul;
                                        else
                                                return "--" + nom + "=" + valeur + precisions;
                                }
                        }
                        return null;
                }
        }
        
/* classe qui lance et surveille un processus VLC (thread) */
                
        //Gere les process de controle vlc
        //fonctionne en parrallele du reste
        class GereProcessus extends Thread
        {
                ParametreVlc[] commande; //commande a executer arguments separes
                public Process processus;
                public boolean enCours = false;
                boolean reagirFinProc = true;
                EncadreProc appelant;        //objet appelant, a prevenir en cas de fin
                
                GereProcessus( ParametreVlc[] comm, EncadreProc objAppelant )
                {
                        super();
                        commande = comm;
                        appelant = objAppelant;
                }
                
                public void terminer()
                {
                        if( enCours )
                        {
                                processus.destroy();
                        }
                }
                
                public void terminer( boolean reagir )
                {
                        if( enCours )
                        {
                                reagirFinProc = reagir;
                                processus.destroy();
                                enCours = false;
                        }
                }

                public void run()
                {
                        //Lancement du processus
                        if(! enCours )
                        {                                
                                String[] commComp;
                                int nbrArgs = 2; //chemin vers vlc + argument quiet
                                
                                //parcours pour le nombre de parametres non nuls
                                for( int k=0; k < commande.length; k++ )
                                {
                                        if( commande[k].chaine() != null )
                                                nbrArgs++;
                                }
                                
                                commComp = new String[nbrArgs];
                                
                                //chemin vers vlc
                                commComp[0] = chmVlc;
                                //parametres donnes : tableau compact
                                for( int k=0, cpt=1; k < commande.length; k++ )
                                {
                                        if( commande[k].chaine() != null )
                                        {
                                                commComp[cpt] = commande[k].chaine();
                                                cpt++;
                                        }
                                }
                                //parametre pour ne rien afficher dans la console
                                commComp[nbrArgs - 1] = "--quiet";
                                
                                try
                                {
                                        Runtime r = Runtime.getRuntime();
                                        processus = r.exec( commComp );
                                        enCours = true;
                                        processus.waitFor();
                                        enCours = false;
                                        //on attend la fin du processus
                                        if( reagirFinProc )
                                                appelant.reagirFinProcessus( );
                                }
                                catch(Exception e)
                                {
                                        System.out.println("erreur d'execution VLC : " + e.toString() );
                                        enCours = false;
                                }
                        }
                }
        }
        
/* Classes qui utilisent gereProcessus pour lire ou enregistrer */
        
        //interface pour d?finir les actions communes
        //de EnrEnCours et LectureEnCours
        interface EncadreProc
        {
                public void reagirFinProcessus();
                public void arreter();
        }
        
        //Gere la lecture en cours
        class LectureEnCours implements EncadreProc
        {
                public boolean enCours = false;
                GereProcessus processus = null;
                
                LectureEnCours()
                {
                        //Cr?ation sans lecture
                }
        
                public void lancerFichier( String nomFichier )
                {
                        if( enCours ) arreter();
                        enCours = true;
                        //lancement du fichier s?lectionn?
                        processus =  new GereProcessus( new ParametreVlc[]{ new ParametreVlc( chmEnregistrements + sepDoss + nomFichier ) }, this );
                        processus.start();
                        
                        
                        //Modif interface
                        labelEnCours.setText( "En cours : " + nomFichier );
                        regarder.setText( "Arreter la lecture" );
                }

                public void lancerChaine()
                {
                        if( enCours ) arreter();
                        enCours = true;
                        //lancement de la chaine selectionnee
                        int indChaine;
                        indChaine = listeAff.getSelectedIndex();
                        if( indChaine >= 0 )
                        {
                                String nomChaine = ((Chaine) listeChaines.elementAt( indChaine ) ).nom;
                                String adresseChaine = ((Chaine) listeChaines.elementAt( indChaine ) ).adresse;

                                processus = new GereProcessus( new ParametreVlc[]{ new ParametreVlc( adresseChaine ) }, this );
                                processus.start();

                                //Modif interface
                                labelEnCours.setText( "En cours : " + nomChaine );
                                regarder.setText( "Arreter la lecture" );
                        }
                }

                //Arret de la lecture en cours
                public void arreter()
                {
                        //arret de la chaine en cours
                        if( enCours )
                        {
                                processus.terminer( false );
                                reagirFinProcessus();
                        }
                }        
                
                //Action en fin de lecture (appele par processus)
                public void reagirFinProcessus()
                {
                        enCours = false;
                        labelEnCours.setText( "En cours :" );
                        regarder.setText( "Regarder la chaine" );                
                }
        }
        
        //Gere un enregistrement en cours
        class EnrEnCours implements EncadreProc
        {
                public boolean enCours = false;
                GereProcessus processus = null;
                public Date momentDep = null;
                public String nomFichier = "";
                public int indChaine = 0;
                public long ancTailleFic = 0;
                public boolean enrProgramme = false;
                int nbrReprises = 0;
                Programmation progParent = null;
                
                EnrEnCours( int chaine, String fichier )
                {
                        //Creation d'un enregistrement en cours 
                        Calendar maintenant = Calendar.getInstance();
                        indChaine = chaine;
                        momentDep = maintenant.getTime();
                        nomFichier = fichier;
                        lancerEnr();
                }
                
                void lancerEnr( )
                {
                        String adresseChaine = ((Chaine) listeChaines.elementAt( indChaine )).adresse;
                        String fic = nomFichier;
                        if( nbrReprises > 0 )
                            fic = "reprise" + nbrReprises + "_" + fic;
                        ParametreVlc[] aFaire = new ParametreVlc[]{ new ParametreVlc( adresseChaine ), new ParametreVlc( "sout", "#standard", "{access=file,mux=ts,url=" + chmEnregistrements + sepDoss + fic + "}" ), new ParametreVlc( "intf", "dummy" ), new ParametreVlc( "--dummy-quiet", ParametreVlc.WINDOWS ) };
                        processus = new GereProcessus( aFaire, this );
                        //on lance le thread
                        processus.start();
                        
                        enCours = true;   
                }
                
                public void setProgParent( Programmation progParent )
                {
                        //on attribue a l'enregistrement une programmation
                        //dont il depend
                        //il l'apellera s'il s'arrete
                        this.progParent = progParent;
                        enrProgramme = ( progParent != null );
                }
                
                public Programmation getProgParent()
                {
                        return progParent;
                }
                
                //Arret de l'enregistrement
                public void arreter()
                {
                        if( enCours )
                        {
                                processus.terminer( false );
                                enCours = false;
                                majListeEnrEnCours();
                        }
                }
                
                //relance d'un enregistrement
                public void relancer()
                {
                        if( enCours )
                        {
                                nbrReprises++;
                                processus.terminer( false );
                                lancerEnr();
                        }
                }
        
                //Action en fin du processus d'enregistrement
                public void reagirFinProcessus()
                {
                        //on relance, pas de raison que ca s'arrete tout seul
                        relancer();
                }
        }
        
/* Classe qui gere les programmations : utilise la classe EnrEnCours */
        
        //Repr?sente un enregistrement programm?
        //fonctionne en parrall?le du reste
        class Programmation extends Thread
        {
                
                //infos enregitrement
                public String nom;
                public int idChaine;
                
                //infos ?tat
                public boolean enCours = false;
                public boolean fini = false;
                
                //Heures
                public int heureDep;
                public int minuteDep;
                public int heureFin;
                public int minuteFin;
                
                //Date ponctuelle
                public int jour;
                public int mois;
                public int annee;
                
                //Dates r?p?titives
                public Vector jours;
                
                //r?p?titif ou ponctuel
                public boolean estPonctuel;
                
                //reprises si erreurs
                public int nbrReprises = 0;
                String suffixeReprises = "";
                
                
                //Utiles
                Calendar momentDep;
                Calendar momentFin;
                EnrEnCours enr = null;
                java.util.Timer chrono;
                
                public Programmation( String nom, int idChaine, int jour, int mois, int annee, int heureDep, int minuteDep, int heureFin, int minuteFin )
                {
                        //Cr?e une programmation ? partir d'une date ponctuelle
                        this.estPonctuel = true;
                        this.nom = nom;
                        this.idChaine = idChaine;
                        this.jour = jour;
                        this.mois = mois;
                        this.annee = annee;
                        this.heureDep = heureDep;
                        this.minuteDep = minuteDep;
                        this.heureFin = heureFin;
                        this.minuteFin = minuteFin;
                        
                        momentDep = Calendar.getInstance();
                        momentFin = Calendar.getInstance();
                        momentDep.set( annee, mois, jour, heureDep, minuteDep, 0 );
                        momentFin.set( annee, mois, jour, heureFin, minuteFin, 0 );
                        
                        //Si changement de jour
                        if( momentFin.before( momentDep ) )
                        {
                                Date tmpFin = momentFin.getTime();
                                tmpFin.setTime( tmpFin.getTime() + 24 * 60 * 60 * 1000 );
                                momentFin.setTime( tmpFin );
                        }
                        
                        //on est parti
                        start();
                }
                
                public Programmation( String nom, int idChaine, Vector jours, int heureDep, int minuteDep, int heureFin, int minuteFin )
                {
                        //Cr?e une programmation ? partir d'une repetition
                        this.estPonctuel = false;
                        this.nom = nom;
                        this.idChaine = idChaine;
                        this.jours = jours;
                        this.heureDep = heureDep;
                        this.minuteDep = minuteDep;
                        this.heureFin = heureFin;
                        this.minuteFin = minuteFin;
                        
                        preparerProgRep( true );
                        
                        //on est parti
                        start();
                }
                
                public Programmation( String nom, EnrEnCours enr, int heureFin, int minuteFin )
                {
                        //Cr?e une programmation ? partir d'un enregistrement d?j? en cours
                        this.enr = enr;
                        enr.setProgParent( this );
                        this.estPonctuel = true;
                        this.nom = nom;
                        idChaine = enr.indChaine;
                        
                        momentDep = Calendar.getInstance();                        
                        momentDep.setTime( enr.momentDep );
                                                
                        momentFin = Calendar.getInstance();
                        momentFin.set( Calendar.HOUR_OF_DAY, heureFin );
                        momentFin.set( Calendar.MINUTE, minuteFin );
                        momentFin.set( Calendar.SECOND, 0 );
                        
                        //Si changement de jour
                        if( momentFin.before( momentDep ) )
                        {
                                Date tmpFin = momentFin.getTime();
                                tmpFin.setTime( tmpFin.getTime() + 24 * 60 * 60 * 1000 );
                                momentFin.setTime( tmpFin );
                        }
                        enCours = true;
                        
                        jour = momentDep.get( Calendar.DAY_OF_MONTH );
                        mois = momentDep.get( Calendar.MONTH );
                        annee = momentDep.get( Calendar.YEAR );
                        heureDep = momentDep.get( Calendar.HOUR_OF_DAY );
                        minuteDep = momentDep.get( Calendar.MINUTE );
                        this.heureFin = momentFin.get( Calendar.HOUR_OF_DAY );
                        this.minuteFin = momentFin.get( Calendar.MINUTE );
                        
                        //on est parti
                        start();
                        
                        majListeEnrEnCours();
                }
                
                public Programmation()
                {
                        //Cr?e un objet vide pour appel de progDeTexte
                }
                
                //renvoie une repr?sentation textuelle de la programmation
                public String repTexte()
                {
                        String chaine = "";
                        chaine+= "<programmation>";
                        chaine+= "\n\t<nom>" + nom.replaceAll( "<", "&lt;" ).replaceAll( ">", "&gt;" ) + "</nom>";
                        chaine+= "\n\t<adresseChaine>" + ((Chaine) listeChaines.elementAt( idChaine )).adresse.replaceAll( "<", "&lt;" ).replaceAll( ">", "&gt;" ) + "</adresseChaine>";
                        chaine+= "\n\t<heureDep>" + heureDep + ":" + minuteDep + "</heureDep>";
                        chaine+=  "\n\t<heureFin>" + heureFin + ":" + minuteFin + "</heureFin>";
                        if( estPonctuel )
                        {
                                chaine+= "\n\t<date>" + jour + "/" + mois + "/" + annee + "</date>";
                        }
                        else
                        {
                                for( int k=0; k < jours.size(); k++ )
                                {
                                        chaine+= "\n\t<jour>";
                                        switch( ((Integer) jours.elementAt( k )).intValue() )
                                        {
                                                case Calendar.MONDAY:
                                                        chaine+= "lundi";
                                                        break;
                                                case Calendar.TUESDAY:
                                                        chaine+= "mardi";
                                                        break;
                                                case Calendar.WEDNESDAY:
                                                        chaine+= "mercredi";
                                                        break;
                                                case Calendar.THURSDAY:
                                                        chaine+= "jeudi";
                                                        break;
                                                case Calendar.FRIDAY:
                                                        chaine+= "vendredi";
                                                        break;
                                                case Calendar.SATURDAY:
                                                        chaine+= "samedi";
                                                        break;
                                                case Calendar.SUNDAY:
                                                        chaine+= "dimanche";
                                                        break;
                                        }
                                        chaine+= "</jour>";
                                }
                        }
                        chaine+= "\n</programmation>";
                        return chaine;
                }
                
                //Cr?e et renvoie une programmation ? partir d'une repr?sentation textuelle
                public Programmation progDeTexte( String chaine )
                {
                        Pattern masqueProg = Pattern.compile( "<programmation>(.*?)</programmation>", Pattern.DOTALL );
                        Matcher trouveurProg = masqueProg.matcher( chaine );
                        if(! trouveurProg.find() )
                                return null;
                        String strProg = trouveurProg.group( 1 );
                        
                        Pattern masqueNom = Pattern.compile( "<nom>\\s*([^<>]*)\\s*</nom>" );
                        Matcher trouveurNom = masqueNom.matcher( strProg );
                        if(! trouveurNom.find() )
                                return null;
                        String nomO = trouveurNom.group( 1 );
                        
                        Pattern masqueChaine = Pattern.compile( "<adresseChaine>\\s*([^<>]*)\\s*</adresseChaine>" );
                        Matcher trouveurChaine = masqueChaine.matcher( strProg );
                        if(! trouveurChaine.find() )
                                return null;
                        String addrChaineO = trouveurChaine.group( 1 );
                        int idChaineO = -1;
                        int k = 0;
                        while( k < listeChaines.size() && idChaineO == -1 )
                        {
                                Chaine chaineT = (Chaine) listeChaines.elementAt( k );
                                if( chaineT.adresse.equals( addrChaineO ) )
                                        idChaineO = k;
                                k++;
                        }
                        if( idChaineO == -1 )
                                return null;
                        
                        Pattern masqueHeureDep = Pattern.compile( "<heureDep>\\s*([0-9]{1,2}):([0-9]{1,2})\\s*</heureDep>" );
                        Matcher trouveurHeureDep = masqueHeureDep.matcher( strProg );
                        if(! trouveurHeureDep.find() )
                                return null;
                        int heureDepO = Integer.parseInt( trouveurHeureDep.group( 1 ) );
                        int minuteDepO = Integer.parseInt( trouveurHeureDep.group( 2 ) );
                        
                        Pattern masqueHeureFin = Pattern.compile( "<heureFin>\\s*([0-9]{1,2}):([0-9]{1,2})\\s*</heureFin>" );
                        Matcher trouveurHeureFin = masqueHeureFin.matcher( strProg );
                        if(! trouveurHeureFin.find() )
                                return null;
                        int heureFinO = Integer.parseInt( trouveurHeureFin.group( 1 ) );
                        int minuteFinO = Integer.parseInt( trouveurHeureFin.group( 2 ) );
                        
                        Pattern masqueDate = Pattern.compile( "<date>\\s*([0-9]{1,2})/([0-9]{1,2})/([0-9]{4})\\s*</date>" );
                        Matcher trouveurDate = masqueDate.matcher( strProg );
                        if( trouveurDate.find() )
                        {
                                int jourO = Integer.parseInt( trouveurDate.group( 1 ) );
                                int moisO = Integer.parseInt( trouveurDate.group( 2 ) );
                                int anneeO = Integer.parseInt( trouveurDate.group( 3 ) );
                                return new Programmation( nomO, idChaineO, jourO, moisO, anneeO, heureDepO, minuteDepO, heureFinO, minuteFinO );
                        }
                        else
                        {
                                Pattern masqueJour = Pattern.compile( "<jour>\\s*([^<>]*?)\\s*</jour>" );
                                Matcher trouveurJour = masqueJour.matcher( strProg );
                                Vector joursO = new Vector();
                                while( trouveurJour.find() )
                                {
                                        String repJour = trouveurJour.group( 1 );
                                        if( repJour.equals( "lundi" ) )
                                                joursO.add( new Integer( Calendar.MONDAY ) );
                                        else if( repJour.equals( "mardi" ) )
                                                joursO.add( new Integer( Calendar.TUESDAY ) );
                                        else if( repJour.equals( "mercredi" ) )
                                                joursO.add( new Integer( Calendar.WEDNESDAY ) );
                                        else if( repJour.equals( "jeudi" ) )
                                                joursO.add( new Integer( Calendar.THURSDAY ) );
                                        else if( repJour.equals( "vendredi" ) )
                                                joursO.add( new Integer( Calendar.FRIDAY ) );
                                        else if( repJour.equals( "samedi" ) )
                                                joursO.add( new Integer( Calendar.SATURDAY ) );
                                        else if( repJour.equals( "dimanche" ) )
                                                joursO.add( new Integer( Calendar.SUNDAY ) );
                                }
                                if( joursO.size() == 0 )
                                        return null;
                                return new Programmation( nomO, idChaineO, joursO, heureDepO, minuteDepO, heureFinO, minuteFinO );
                        }
                }
                
                //Pr?pare le prochain enregistrement r?p?t?
                void preparerProgRep( boolean accepterEnrDejaCommence )
                {
                        //accepterEnrDejaCommence : seulement pour la premi?re fois
                        //on place le calendrier de d?part ? aujourd'hui
                        momentDep = Calendar.getInstance();
                        momentFin = Calendar.getInstance();
                        momentDep.set( Calendar.HOUR_OF_DAY, heureDep );
                        momentDep.set( Calendar.MINUTE, minuteDep );
                        momentDep.set( Calendar.SECOND, 0 );
                        momentFin.set( Calendar.HOUR_OF_DAY, heureFin );
                        momentFin.set( Calendar.MINUTE, minuteFin );
                        momentFin.set( Calendar.SECOND, 0 );
                        
                        boolean aujourdhuiOk;
                        if( accepterEnrDejaCommence )
                                aujourdhuiOk = momentFin.after( Calendar.getInstance() );
                        else
                                aujourdhuiOk = momentDep.after( Calendar.getInstance() );
                        
                        //jour actuel
                        int jourAct = Calendar.getInstance().get( Calendar.DAY_OF_WEEK );
                        int minJoursAj = 10;
                        
                        for( int k=0; k < jours.size(); k++ )
                        {
                                int joursAj = ((Integer) jours.elementAt( k )).intValue() - jourAct;
                                if( joursAj < 0 || ( joursAj == 0 && ! aujourdhuiOk ) )
                                        joursAj += 7;
                                if( joursAj < minJoursAj )
                                        minJoursAj = joursAj;
                        }
                        //on a le nombre minimum de jours ? ajouter
                        Date dtDep = momentDep.getTime();
                        dtDep.setTime( dtDep.getTime() + minJoursAj * 24 * 60 * 60 * 1000 );
                        momentDep.setTime( dtDep );
                        Date dtFin = momentFin.getTime();
                        dtFin.setTime( dtFin.getTime() + minJoursAj * 24 * 60 * 60 * 1000 );
                        momentFin.setTime( dtFin );
                        
                        //Si changement de jour
                        if( momentFin.before( momentDep ) )
                        {
                                Date tmpFin = momentFin.getTime();
                                tmpFin.setTime( tmpFin.getTime() + 24 * 60 * 60 * 1000 );
                                momentFin.setTime( tmpFin );
                        }
                }
                
                void lancerEnr()
                {
                        //lance l'enregistrement et le timer de fin
                        if( momentFin.after( Calendar.getInstance() ))
                        {
                                String nomChaine = ((Chaine) listeChaines.elementAt( idChaine ) ).nom;
                                Calendar maintenant = Calendar.getInstance();
                                String prefFichier = simpChaine( nomChaine ) + "-" + maintenant.get( Calendar.DAY_OF_MONTH ) + "-" + maintenant.get( Calendar.MONTH ) + "-" + maintenant.get( Calendar.YEAR ) + "-" + maintenant.get( Calendar.HOUR_OF_DAY ) + "h" + maintenant.get( Calendar.MINUTE ) + "-";
                                enr = new EnrEnCours( idChaine, prefFichier + nom + suffixeReprises + extVideo );
                                enr.setProgParent( this );
                                
                                enrEnCours.add( enr );
                                majListeEnrEnCours();
                                
                                enCours = true;
                                chrono = new java.util.Timer();
                                chrono.schedule( new TacheTimer( TacheTimer.FINIR ), momentFin.getTime() );
                        }
                        else
                        {
                                rafraichirFinEnregistrement();
                        }
                        majListeProg();                        
                }
                
                //un enregistrement est termine
                //on arrete si ponctuel
                //ou on relance
                void rafraichirFinEnregistrement( )
                {
                        if( estPonctuel )
                        {
                                fini = true;
                        }
                        else
                        {
                                preparerProgRep( false );
                                chrono = new java.util.Timer();
                                chrono.schedule( new TacheTimer( TacheTimer.LANCER ), momentDep.getTime() );
                        }                        
                }
                
                void finirEnr()
                {
                        //termine l'enregistrement
                        //et supprime la programmation
                        //ou la reinitialise
                        chrono.cancel();
                        enCours = false;
                        enr.arreter();
                        rafraichirFinEnregistrement();
                        majListeProg();
                }
                
                public void arreterEnrEnCours()
                {
                        //On arrete l'enregistrement et on supprime la programmation si necessaire
                        finirEnr();
                }
                
                public void supprimer()
                {
                        if( enCours )
                                arreterEnrEnCours();
                        chrono.cancel();
                }
                
                public void run()
                {
                        //Lance le timer de d?but
                        //ou l'enregistrement si necessaire
                        //si l'enregistrement est deja la, lance le timer de fin
                        if(! enCours )
                        {
                                if( momentDep.before( Calendar.getInstance() ) )
                                {
                                        lancerEnr();
                                }
                                else
                                {
                                        chrono = new java.util.Timer();
                                        chrono.schedule( new TacheTimer( TacheTimer.LANCER ), momentDep.getTime() );
                                }
                        }
                        else
                        {
                                if( momentFin.before( Calendar.getInstance() ) )
                                {
                                        finirEnr();
                                }
                                else
                                {
                                        chrono = new java.util.Timer();
                                        chrono.schedule( new TacheTimer( TacheTimer.FINIR ), momentFin.getTime() );
                                }
                        }
                }
                
                //objet qui effectue lancerEnr ou finirEnr quand prevu
                class TacheTimer extends TimerTask
                {
                        int tache;
                        static final int LANCER = 0;
                        static final int FINIR = 1;
                        public TacheTimer( int tache )
                        {
                                this.tache = tache;
                        }
                        
                        public void run()
                        {
                                if( tache == LANCER )
                                {
                                        lancerEnr();
                                }
                                else if( tache == FINIR )
                                {
                                        finirEnr();
                                }
                        }
                }
        }
}
