package w3c.rtsp.client;

// mediascape.java
// $Id: mediascape.java,v 1 1997/07/10 15:00 osofia Exp $
// (c) COPYRIGHT MIT and INRIA, 1997.
// Please first read the full copyright statement in file COPYRIGHT.html

import java.io.*;
import java.util.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import w3c.rtsp.common.*;

public class mediascape {

  RtspClient client=null;
  RtspURL serverurl=null;
  StringBuffer buffer;
  TextField  Texte=null;
  Process audio_p=null,video_p=null;
  static String clientHostName=null;

  int currentPosition=0;

  //prog_in_use is true if the prog used to listen is running.
  //setup is true if the setup message has been sent.
  //no_problem is true if there aren't exception thrown.
  //session_in_use is true if a session is running.

  boolean audio_in_use=false,video_in_use=false,setup=false,no_problem=true,session_in_use=false,describe=false,remove=false;

  //presentation.

 protected Frame myframe=null;
 protected MenuBar MB=null;;
 protected Menu menu1=null,menu2=null,menu3=null,menu4=null;
 protected MenuItem menuitem1=null;
 protected MenuItem menuitem2=null;
 protected MenuItem menuitem3=null;
 protected MenuItem menuitem4=null;
 protected MenuItem menuitem5=null;
 protected MenuItem menuitem6=null;
 protected MenuItem menuitem7=null;
 protected MenuItem menuitem8=null;
 protected MenuItem menuitem9=null;

  //configuration.

 protected Properties myProp=null;
 protected int default_port_nb=8004;
 protected int last_port=-1;
 protected String last_host=null;
 protected String default_prog_audio_used=new String("vat -r");
 protected String default_prog_video_used=new String("vic");
 protected String default_stream_protocol=new String("RTP");
 protected int port_nb=default_port_nb;
 protected String prog_used=default_prog_audio_used;
 protected String audio_prog_used=default_prog_audio_used;
 protected String video_prog_used=default_prog_video_used;
 protected String stream_protocol=default_stream_protocol;
 protected String default_config=new String("file.conf");
 protected File file_conf=new File(default_config);
 protected TextField atpg=null,vtpg=null,tpt=null,tp=null;
 protected TextField datpg=null,dvtpg=null,dtpt=null,dtp=null;
 protected int videoport=8004;
 protected int audioport=8006;
 protected String audiolastprog=null,videolastprog=null;

  //if there are exception thrown we catch them and display a DialogBox.

 protected choose myC;
 protected MyActionListener myListener=null;
 protected DialogBox dialogB=null,dialogB1=null,dialogB2=null;
 protected DialogBox dialogB3=null,dialogB4=null,dialogB5=null,dialogB6=null;
 protected DialogBox dialogB7=null,dialogB8=null;
 protected int idSession=-1;
 protected TextField dialogBoxText=null;


  //tabItem is a vector where we can find all element of the bookmarks.

  protected String bitem=new String();
  protected Vector tabMenuItem=new Vector();
  public ItemListener itemListener=null;


  public mediascape() {

    myframe = new Frame("Mediascape");
    Dimension dim=new Dimension(450,200);
    myframe.setSize(dim);

    //loading the default configuration file.

    myProp=new Properties();
    BufferedInputStream buff = null;
    try {
      buff = new BufferedInputStream( new FileInputStream(file_conf));
      myProp.load(buff);
      buff.close();
    } catch (IOException e) {
      System.out.println(e.getMessage());
      e.printStackTrace();
      try { 
	if (buff != null) buff.close(); 
      } catch (Exception ex) {}
    }

    audio_prog_used=myProp.getProperty("audioprogram");
    video_prog_used=myProp.getProperty("videoprogram");
    stream_protocol=myProp.getProperty("protocol");
    port_nb=Integer.parseInt(myProp.getProperty("port"));

    dialogBoxText=new TextField(40);
    atpg=new TextField(20);
    vtpg=new TextField(20);
    tpt=new TextField(20);
    tp=new TextField(20);
    datpg=new TextField(20);
    dvtpg=new TextField(20);
    dtpt=new TextField(20);
    dtp=new TextField(20);
    myC=new choose();

    myListener=new MyActionListener(this);

    dialogB=new DialogBox("You have to give your port number",this);
    dialogB1=new DialogBox("404 Not Found",this);
    dialogB2=new DialogBox("Program Not Found",this);
    dialogB4=new DialogBox("Url's site :",dialogBoxText,this);


    //creating the dialog box to configure the appli.t for TextField and d for default TextField.

    atpg.setText(audio_prog_used);
    vtpg.setText(video_prog_used);
    tpt.setText(stream_protocol);
    tp.setText(Integer.toString(port_nb));

    datpg.setText(default_prog_audio_used);
    dvtpg.setText(default_prog_video_used);
    dtpt.setText(default_stream_protocol);
    dtp.setText(Integer.toString(default_port_nb));

    dialogB5=new DialogBox(atpg,vtpg,tpt,tp,this);
    dialogB6=new DialogBox(datpg,dvtpg,dtpt,dtp,this);

    GridBagLayout myGBL;

    this.MB=new MenuBar();
    this.menu1=new Menu("File");
    this.menu2=new Menu("Options");
    this.menu4=new Menu("Bookmarks");

    this.menuitem1=new MenuItem("Open Location");
    this.menuitem1.addActionListener(myListener);
    this.menuitem2=new MenuItem("Exit");
    this.menuitem2.addActionListener(myListener);
    this.menuitem3=new MenuItem("General Preferences");
    this.menuitem3.addActionListener(myListener);
    this.menuitem8=new MenuItem("Add Bookmarks");
    this.menuitem8.addActionListener(myListener);
    this.menuitem9=new MenuItem("Remove Bookmarks");
    this.menuitem9.addActionListener(myListener);

    //Text is added to the actionListener to send message if
    //return is pushed.

    myC.myW.Texte.addActionListener(myListener);
    dialogB4.getSample().addActionListener(myListener);

    menu1.add(this.menuitem1);
    menu1.add(this.menuitem2);
    menu2.add(this.menuitem3);
    menu4.add(this.menuitem8);
    menu4.addSeparator();
    menu4.add(this.menuitem9);
    menu4.addSeparator();

    MB.add(menu1);
    MB.add(menu2);
    MB.add(menu4);
    myframe.setMenuBar(this.MB);

    buffer = new StringBuffer();
    addItem("initializing... ");
    myframe.setLayout(myGBL=new GridBagLayout());
    myframe.setLayout(myGBL);

    ((CardLayout)myC.myW.getLayout()).show(myC.myW,"PageDialog1");
    GridBagConstraints myGBC2=new GridBagConstraints();
    myGBC2.insets = new Insets(0,0,10,0);
    myGBC2.anchor=GridBagConstraints.CENTER;
    myGBC2.gridwidth = GridBagConstraints.REMAINDER;
    myGBL.setConstraints(myC.myW,myGBC2);
    myframe.add(myC.myW);
 
    myC.myW.MyButton.addActionListener(myListener);
    myC.myW.MyButton2.addActionListener(myListener);

    myC.myW.Texte.requestFocus();
    loadBookmarks();
  }

  //destroy the application by killing the client and closing the socket.

 public void destroy(){
   stop();
   if(client!=null){
     if(client.receive!=null)
       client.receive.stop();
     client=null;
     System.gc();
     no_problem=true;
   }
   myframe.dispose();
  if(video_p!=null)
     video_p.destroy();
   if(audio_p!=null)
     audio_p.destroy();
   System.exit(0);
   addItem("stopping... ");
 }

  //same thing that destroy but without killing the application.

  public void stop() {
    if(client!=null){
      client.Stop(myC.myW.Texte.getText());
      if(client.receive!=null)
	client.receive.stop();
      describe=false;
      client=null;
      System.gc();
      //   if(video_p!=null)
      //video_p.destroy();
      setup=false;
      no_problem=true;
      session_in_use=false;
    }
  }

  public Dimension minimunSize(){
    return new Dimension(200,200);
  }
  
  public Dimension preferredSize(){
    return new Dimension(400,200);
  }

  public void addItem(String newWord) {
    buffer=new StringBuffer(newWord);
    myframe.repaint();
  }

  //test if the added address isn't in the bookmark file yet.
 
  public boolean inBookmarks(String newEntry){
    for(Enumeration e=tabMenuItem.elements();e.hasMoreElements();)
      if(newEntry.equals(((MenuItem)e.nextElement()).getLabel()))
	return true;
    return false;
  }

  //add the current address to the bookmarks.

  public void addBookmarks(){
    //the text field  myC.myW.Texte is add to the bookmarks.
    System.out.println(inBookmarks(myC.myW.Texte.getText()));
    if(!inBookmarks(myC.myW.Texte.getText())){
      MenuItem newItem=new MenuItem(myC.myW.Texte.getText());
      newItem.addActionListener(myListener);
      System.out.println("\n LABEL MENU :"+newItem.getLabel());
      menu4.add(newItem);
      tabMenuItem.addElement(newItem);
      System.out.println("\nALL ITEM :"+tabMenuItem);
      saveBookmarks();
    }
  }

  //remove the selected item.

  public void removeBookmarks(MenuItem men){
    System.out.println("\removing the menu");
    menu4.remove(men);
    tabMenuItem.removeElement(men);
    saveBookmarks();
    System.out.println("\n"+men.getLabel()+":DELETED");
  }
  

  //write the vector to the bookmarks file.

  public void saveBookmarks(){
    StringBuffer sb=new StringBuffer();
    for(Enumeration e=tabMenuItem.elements();e.hasMoreElements();){
      sb.append(((MenuItem)e.nextElement()).getLabel());
      sb.append("\n");
    }
    System.out.println("\nElement:"+sb);
    try{
      FileWriter fw=new FileWriter(".bookmarks.rtsp");
      fw.write(sb.toString());
      fw.close();
    }catch(IOException E){
      E.printStackTrace();
    }
  }

  //load the bookmarks file.

  public void loadBookmarks(){
    try{
      BufferedReader br=new BufferedReader(
       		      new FileReader(new File(".bookmarks.rtsp")));
      String tmp=null;
      MenuItem Mtmp=null;
      while((tmp=br.readLine())!=null){
	if(tmp.endsWith("\n"))
	  tmp=tmp.substring(0,tmp.indexOf('\n')-1);
	tabMenuItem.addElement(Mtmp=new MenuItem(tmp));
	Mtmp.addActionListener(myListener);
	menu4.add(Mtmp);
      }
      while((tmp=br.readLine())!=null);
      br.close();
    }catch(IOException E){
      ;
    } 
  }

  //creating a choice by parsing the vector containing the MenuItem
  //of the bookmarks.

  public Choice createChoice(Vector vect){
    Choice mychoice=new Choice();
    for(Enumeration enume=tabMenuItem.elements();enume.hasMoreElements();){
      mychoice.add(((MenuItem)enume.nextElement()).getLabel());
	}
    return mychoice;
  }

  //Deleting the vector element specified element by the choice.

  public MenuItem getItem(String item){
    MenuItem men=null;
    if(!item.equals("")){
      System.out.println("\nBITEM: "+bitem);
      for(Enumeration enume=tabMenuItem.elements();enume.hasMoreElements();){
	men=(MenuItem)enume.nextElement();
	if(men.getLabel().equals(item))
	  return men;
      }
    }
    System.out.println("\nELEMENTS NOT FOUND");
    return null;
  }

  public static void main(String []arg){
    mediascape app=new mediascape();
    app.myframe.show();
  }


    // Construct the server objetc RtspURL.

  public void constructServerUrl(String addr){
    try{
      serverurl=new RtspURL(addr);
    }catch(MalformedURLException E){
      System.out.println("\nERREUR URL :");
      E.printStackTrace();
      dialogB1.display("");
      stop();
    }catch(IOException E){
      System.out.println("\nERREUR I/O :");
      E.printStackTrace();
      stop();
    }
  }
    
    //instanciate the client.

  public void constructClient(String host,int port){
        try{
	client = new RtspClient(host,port);
	session_in_use=true;
      }catch(ConnectException E){
	System.out.println("\nSOCKET I/O :");
	E.printStackTrace();
	dialogB1.display("");
	no_problem=false;
	stop();
      }catch(IOException E){
	System.out.println("\nERREUR I/O :");
	E.printStackTrace();
	stop();
      }

  }

    //ask to the server a description of the document.

   public void describeIt(String doc){
     try{
       if(no_problem==true)
	 client.Describe(doc);
       if(client.getSdpObj().getMedia()!=null){
	 if(!client.getSdpObj().getMedia().isEmpty()){
	   System.out.println("\nUSER MEDIA :"
	          +client.getSdpObj().getMedia().elementAt(0).toString());
	   SdpMedia sm=new SdpMedia();
	   sm=(SdpMedia)client.getSdpObj().getMedia().elementAt(0);
	 }
       }
       if(client.getCode()==200)
	 describe=true;
       
       //we have to change ........ if getcode !=200.
       
     }catch(IOException E){
       E.printStackTrace();
       dialogB1.display("");
       stop();
     }
   }

    //treat the first describe.

   public void doDescribeAtFirst(){
     System.out.println("\nMEDIA :"
			+client.getSdpObj().getMedia().toString()
			+" TAILLE :"
			+client.getSdpObj().getMedia().size());
     SdpMedia med=new SdpMedia();
     SdpMedia med1=null;
     med=(SdpMedia)client.getSdpObj().getMedia().elementAt(0);
     if(client.getSdpObj().getMedia().size()>1)
       med1=(SdpMedia)client.getSdpObj().getMedia().elementAt(1);
     
     //we have two stream.
     
     if(((med.getMedia().equals("audio"))
	 &&
	 ((med1!=null)&&(med1.getMedia().equals("video"))))
	||
	((med.getMedia().equals("video"))
	 &&((med1!=null)
	    &&(med1.getMedia().equals("audio")))))
       {
	 launchAudioAndVideo(audio_prog_used,
			     video_prog_used,serverurl.getHost(),
			     port_nb,port_nb-2);
       }
     
     //we have only one stream.
     
     if((med.getMedia().equals("audio"))&&(med1==null)){
       launchAudio(audio_prog_used,serverurl.getHost(),port_nb);
     }
     if((med.getMedia().equals("video"))&&(med1==null)){
       launchVideo(video_prog_used,serverurl.getHost(),port_nb-2);
     }
   }

 public void doDescribe(){
   describeIt(myC.myW.Texte.getText());
   System.out.println("\nDESCRIBE:"
		      +describe+client.getCode()
		      +" TAILLE :"+client.getSdpObj().getMedia().size());
   if(describe==true){
     System.out.println("\nMEDIA :"
			+client.getSdpObj().getMedia().toString());
     SdpMedia med=new SdpMedia();
     SdpMedia med1 = null;
     med=(SdpMedia)client.getSdpObj().getMedia().elementAt(0);
     if(client.getSdpObj().getMedia().size()>1){
       med1=(SdpMedia)client.getSdpObj().getMedia().elementAt(1);
       System.out.println("\nIn the if:");
     }
     
     //we need two receiver but one has changed.
     
     if(((med.getMedia().equals("audio"))
	 &&
	 ((med1!=null)&&(med1.getMedia().equals("video"))))
	||
	((med.getMedia().equals("video"))
	 &&((med1!=null)&&(med1.getMedia().equals("audio")))))
       {
	 if((audiolastprog!=audio_prog_used)
	    &&(videolastprog!=video_prog_used)){
	   audio_p.destroy();
	   video_p.destroy();
	   launchAudioAndVideo(audio_prog_used,
			       video_prog_used,
			       serverurl.getHost(),
			       port_nb,port_nb-2);
	 }
	 if((audiolastprog!=audio_prog_used)
	    &&
	    (videolastprog==video_prog_used)){
	   if(audio_p!=null)
	     audio_p.destroy();
	   launchAudio(audio_prog_used,serverurl.getHost(),port_nb);
	 }
	 if((audiolastprog==audio_prog_used)
	    &&
	    (videolastprog!=video_prog_used)){
	   if(video_p!=null)
	     video_p.destroy();
	   launchVideo(video_prog_used,serverurl.getHost(),port_nb-2);
	 }
	 if(video_p==null)
	   launchVideo(video_prog_used,serverurl.getHost(),port_nb-2);
	 if(audio_p==null)
	   launchAudio(audio_prog_used,serverurl.getHost(),port_nb);
       }
     
     //we need only the audio receiever.
     
     if((med.getMedia().equals("audio"))&&(audio_p==null)&&(med1==null)){
       if(video_p!=null){
	 video_p.destroy();
	 video_p=null;
	 video_in_use=false;
       }
       launchAudio(audio_prog_used,serverurl.getHost(),port_nb);
     }
     if((med.getMedia().equals("audio"))
	&&
	(audiolastprog==audio_prog_used)&&(med1==null)){
       if(video_p!=null){
	 video_p.destroy();
	 video_p=null;
	 video_in_use=false;
       }
     }
     if((med.getMedia().equals("audio"))
	&&
	(audiolastprog!=audio_prog_used)&&(med1==null)){
       audio_p.destroy();
       if(video_p!=null){
	 video_p.destroy();
	 video_p=null;
	 video_in_use=false;
       }
       launchAudio(audio_prog_used,serverurl.getHost(),port_nb);
     }
     
     if((med.getMedia().equals("audio"))&&(med1==null)){
       if(video_p!=null)
	 video_p.destroy();
       video_p=null;
       video_in_use=false;
       if(audiolastprog!=audio_prog_used){
	 if(audio_p!=null)
	   audio_p.destroy();
	 launchAudio(audio_prog_used,serverurl.getHost(),port_nb);
       }
     }
     
     //we need only the video reveiver.
     
     if((med.getMedia().equals("video"))&&(video_p==null)&&(med1==null)){
       if(audio_p!=null){
	 audio_p.destroy();
	 audio_p=null;
	 audio_in_use=false;
       }
       launchVideo(video_prog_used,serverurl.getHost(),port_nb-2);
     }
     if((med.getMedia().equals("video"))
	&&
	(videolastprog==video_prog_used)&&(med1==null)){
       if(audio_p!=null){
	 audio_p.destroy();
	 audio_p=null;
	 audio_in_use=false;
       }
     }
     if((med.getMedia().equals("video"))
	&&
	(videolastprog!=video_prog_used)&&(med1==null)){
       if(video_p!=null){
	 video_p.destroy();
	 video_p=null;
	 video_in_use=false;
       }
       if(audio_p!=null){
	 audio_p.destroy();
	 audio_p=null;
	 audio_in_use=false;
       }
       launchVideo(video_prog_used,serverurl.getHost(),port_nb-2);
     }
   }
 }

    //play the document specified.

    public void doPlay(String addr){
      try{
	client.Play(myC.myW.Texte.getText());
      }catch(IOException E){
	E.printStackTrace();
	dialogB1.display("");
	stop();
      }
      if(client.getCode()==406)
	dialogB1.display("");
	if(client.getCode()==404)
	  dialogB1.display("");
	client.setCode(-1);
    }
  
    //launch the session and look after every events.

  public void SessionGo(){
    stop();

    // if audio/video helpers were started, check if they're still running

    if (audio_in_use==true) {
      try {
        audio_p.exitValue();
        audio_in_use = false;
      }
      catch (IllegalThreadStateException I){
        ;
      }
    }
    if (video_in_use==true) {
      try {
        video_p.exitValue();
        video_in_use = false;
      }
      catch (IllegalThreadStateException I){
        ;
      }
    }

    if((audio_in_use!=true)&&(video_in_use!=true))
    {
      constructServerUrl(myC.myW.Texte.getText());
      constructClient(serverurl.getHost(),serverurl.getPort());
      
      if(!myC.myW.Texte.getText().equals(""))
	describeIt(myC.myW.Texte.getText());
      
      //Describe below.
      
      System.out.println("\nDESCRIBE:"+describe+client.getCode());
      
      //we will have to send few setups
      // if the document consists in few basic document.

      if(setup!=true){
	client.SendMessage("SETUP",myC.myW.Texte.getText(),port_nb);
	setup=true;
      }

      if(describe==true){
	doDescribeAtFirst();
      }
      else{
	if(audio_p==null)
	  launchAudio(audio_prog_used,serverurl.getHost(),port_nb);
      }

      if(!myC.myW.Texte.getText().equals(""))
	doPlay(myC.myW.Texte.getText());
      else
	dialogB1.display("");
      addItem("STILL PLAYING \n");
    }

    //one of the programs used to receive data is already in use.

    else {
      if(audio_p!=null)
      System.out.println("\nAUDIO RECEIVER ALREADY ACTIVE");
      if(video_p!=null)
	System.out.println("\nVIDEO RECEIVER ALREADY ACTIVE");
      constructServerUrl(myC.myW.Texte.getText());
      constructClient(serverurl.getHost(),serverurl.getPort());
    
   //Describe below.
      
      if(!myC.myW.Texte.getText().equals(""))
	doDescribe();
      else{
	if(audio_p==null)
	  launchAudio(audio_prog_used,serverurl.getHost(),port_nb);
      }
      
      //we can have case of multiple setup (depend on describe).
      
      if(setup!=true){
	client.SendMessage("SETUP",myC.myW.Texte.getText(),port_nb);
	setup=true;
      }
      if(!myC.myW.Texte.getText().equals(""))
	doPlay(myC.myW.Texte.getText());
      else
	dialogB1.display("");
      addItem("STILL PLAYING \n");
    }
  }
  
  //the process p is used to launch the audio receiver.
  //the process video_p is used to launch the video receiver.

  //launch only the audio receiver.
  
  public void launchAudio(String progToLaunch,String hostAddress,int port){
    Runtime run=Runtime.getRuntime(); 
    try{
      audio_p=run.exec(progToLaunch+" "+hostAddress+"/"+port);
      audiolastprog=progToLaunch;
      audio_in_use=true;
      video_in_use=false;
    }catch(IOException E){
      E.printStackTrace();
      dialogB1.display("");
      stop();
    }
  }

  //launch only the video receiver.
 
  public void launchVideo(String progToLaunch,String hostAddress,int port){
    Runtime run=Runtime.getRuntime(); 
    try{
      video_p=run.exec(progToLaunch+" "+hostAddress+"/"+port);
      videolastprog=progToLaunch;
      video_in_use=true;
      audio_in_use=false;
    }catch(IOException E){
      E.printStackTrace();
      dialogB1.display("");
      stop();
    }
  }

  //launch both video and audio receiver.
  
  public void launchAudioAndVideo(String progAudio,
				  String progVideo,
				  String hostAddress,
				  int audioport,
				  int videoport){
    Runtime run=Runtime.getRuntime(); 
    Runtime run1=Runtime.getRuntime(); 
    try{
      audio_p=run.exec(progAudio+" "+hostAddress+"/"+audioport);
      video_p=run.exec(progVideo+" "+hostAddress+"/"+videoport);
      audiolastprog=progAudio;
      videolastprog=progVideo;
      audio_in_use=true;
      video_in_use=true;
    }catch(IOException E){
      E.printStackTrace();
      dialogB1.display("");
      stop();
    }
  }
}
