package com.videonext.mplayer.internal;

import java.net.*;
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class MediaExporter {

    private ExportThread exportThread = null;    
    private MediaExporterListener listener = null;

    public MediaExporter()
    {
    } 

    public void setMediaExporterListener(MediaExporterListener listener) {
        this.listener = listener;
    }

   public boolean startExport(String url,
                              String outFilename)
   {
      if ( outFilename == null || outFilename.length() == 0)
      {
         System.out.println("Output file name is not specified.");
         return false;
      }

      try 
      {
          exportThread = new ExportThread(url, outFilename);
      } 
      catch (MalformedURLException ex) 
      {
          ex.printStackTrace();
          
          return false;
      }         
      
      exportThread.start();                  

      
      return true;
        
   }
     
   public void cancelExport()
   {
      if (exportThread != null)
      {
         exportThread.cancel();
      }
   }
     
   
   class ExportThread extends Thread
   {
      private Boolean canceled   = false;
      private String outFileName = null;
      private String url = null;
    	 
      public ExportThread(String url, 
                          String filename) throws MalformedURLException
      {   		 
         super("ExportThread");
         setDaemon(true);
         
         this.url = url;
         this.outFileName = filename;    	

      }
    	  
      public void cancel()
      {
         canceled = true;
      }
    	 
      @SuppressWarnings("deprecation")
	public void run()
      {
         RandomAccessFile of = null;
         DataInputStream is = null;
         OutputStream    os = null;
         Boolean success = false; 

         try
         {           	    
            String host  = getHostFromURL(url); 
            int    port  = getPortFromURL(url, 8554); 

            Socket socket = new Socket(host, port);

            is = new DataInputStream(socket.getInputStream());
            os = socket.getOutputStream();

            System.out.println("Connected to " + host + ":" + port);

            String req = "XEXPORT " + url + " RTSP/1.0\r\nCSeq: 1\r\n\r\n";
         
            System.out.println("Request:");
            System.out.println(req);

            os.write(req.getBytes());

            String resp  = is.readLine();
            boolean signed = false;

            while (true) 
            {       
               String line =  is.readLine();
               if (line == null || line.length() == 0)
                  break;

               if (line.contains("X-Signed: yes"))
                  signed = true;

//            resp += line + "\r\n";
            }

            System.out.println("Response:");
            System.out.println(resp);
          
            if (!resp.contains("RTSP/1.0 200"))
            {
               socket.close();
               throw new Exception("Request failed. Server returns: "  + resp);
            }

				
            byte data[] = new byte[65536*4];
            String header, contentType = null;
            int contentLength = -1; 
            int oldprogress = 0, progress = 0;
            long seek = 0;
            long clipSize = 0;

            Pattern contentTypeRegex       = Pattern.compile("^Content-Type: (.+)");
            Pattern contentLengthRegex     = Pattern.compile("^Content-Length: (.+)");
            Pattern xProgressRegex         = Pattern.compile("^X-Progress: (.+)%");
            Pattern xSeekRegex             = Pattern.compile("^X-Seek: (.+)");
            	  
            System.out.println("Downloading " + outFileName + " from " + url);

            of = new RandomAccessFile(outFileName, "rw");
            of.setLength(0);

            while ((header = is.readLine()) != null && !canceled)
            {
               Matcher m;
               if ((m=contentTypeRegex.matcher(header)).find())
               {
                  contentType = m.group(1);
               }
               else if ((m=contentLengthRegex.matcher(header)).find())
               {
                  contentLength = Integer.parseInt(m.group(1));
               }
               else if ((m=xProgressRegex.matcher(header)).find())
               {
                  progress = Integer.parseInt(m.group(1));
               }
               else if ((m=xSeekRegex.matcher(header)).find())
               {
                  seek = Long.parseLong(m.group(1));
               }

               if (header.length() == 0 && contentLength >= 0)
               { 
                  if (contentLength == 0 && progress == 100) // we are done..
                  {
                     success = true;
                     if (signed && !(data[4] == 'd' && data[5] == 's' && data[6] == 'i' && data[7] == 'g'))
                     {
                        // container is not signed.
                         if (listener != null)
                             listener.newDataChunk(0, 100, "Digital signature is missing in the movie. Please contact your system administrator.");
                     }
                     else
                     {
                         if (listener != null)
                             listener.newDataChunk(0, 100, "");
                     }
                     break;
                  }

                  int bytesRead = 0;
                  while (bytesRead < contentLength)
                  {
                     int ret = is.read(data, bytesRead, contentLength - bytesRead);
                     if (ret <= 0)
                     {
                        System.out.println("ERROR ret <= 0");
                         if (listener != null)
                             listener.newDataChunk(0, 0, "Read data from network failed");
                        break;
                	                
                     }
                     bytesRead += ret;
                  }

                	      
                  if (!contentType.equalsIgnoreCase("video/quicktime"))
                  {
                     System.out.println("ERROR: content type is " + contentType);
                     System.out.println(new String(data));

                     if (listener != null)
                         listener.newDataChunk(0, 0, "Export failed due server issues");

                     break;
                  }
                  
                  clipSize += contentLength;
                  
                  /*
                    System.out.println("read " + contentLength +" bytes");
                    System.out.println("progress: " + progress);
                    System.out.println("seek: " + seek);
                  */
                  if (oldprogress != progress)
                  {
                     if (listener != null)
                         listener.newDataChunk(clipSize, progress, "");

                     oldprogress = progress;
                  }

                  if (seek != 0)
                  {
                     of.seek(seek);
                     seek = 0;
                  }
                	       
                  of.write(data, 0, contentLength);
                	        
                  contentLength = -1;
               }    
            }
            

            if (of != null) of.close();
            if (is != null) is.close();
            if (os != null) os.close();
          
         }
         catch (Exception ex) 
         {
            System.err.println("Error: " + ex.toString());
            ex.printStackTrace(System.err);

            if (listener != null)
                listener.newDataChunk(0, 0, "Requested video fragment is not available in videoarchive");
         }
         
         
         if (success)
         {
            System.out.println(outFileName + " downloaded successfully");
         }
         else  
         {	
            new File(outFileName).delete();
         		
            System.out.println(outFileName + " download failed");
         }
         
      }

      private int getPortFromURL(String url, int defaultPort) 
      {
         // Trim schema and path
         String hostStr = null;
         int sepIdx = url.indexOf("//");
         if (sepIdx < 0) return defaultPort;
         hostStr = url.substring(sepIdx + 2);
         sepIdx = hostStr.indexOf("/");
         if (sepIdx < 0) return defaultPort;
         hostStr = hostStr.substring(0, sepIdx);
    
         sepIdx = hostStr.indexOf(':');
         if (sepIdx < 0) 
         {
            return defaultPort;
         } 
         else 
         {
            String portStr = hostStr.substring(sepIdx + 1).trim();
            try 
            {
               return Integer.parseInt(portStr);
            } 
            catch (NumberFormatException e) 
            {
               return defaultPort;
            }
         }
      }

      private String getHostFromURL(String url) 
      {
         // Trim schema and path
         String hostStr = null;
         int sepIdx = url.indexOf("//");
         if (sepIdx < 0) return "";
         hostStr = url.substring(sepIdx + 2);
         sepIdx = hostStr.indexOf("/");
         if (sepIdx < 0) return "";
         hostStr = hostStr.substring(0, sepIdx);
    

         sepIdx =  hostStr.indexOf(':');
         if (sepIdx < 0) 
         {
            return hostStr;
         } 
         else 
         {
            return hostStr.substring(0, sepIdx);
         }
      }

   }

	 
}
