import java.net.Socket;
import java.net.URL;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.impl.DefaultHttpClientConnection;
import org.apache.http.message.BasicHttpRequest;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.BasicHttpProcessor;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestExecutor;
import org.apache.http.protocol.RequestContent;
import org.apache.http.protocol.RequestTargetHost;
import org.apache.http.util.EntityUtils;
import org.serviio.library.metadata.MediaFileType;
import org.serviio.library.online.ContentURLContainer;
import org.serviio.library.online.FeedItemUrlExtractor;
import org.serviio.library.online.PreferredQuality;



public class MegavideoPlugin  extends FeedItemUrlExtractor{
	
		//Base uri for getting video Info
		private static String baseInfoUri = "http://www.megavideo.com/xml/videolink.php?v=";
	    public MegavideoPlugin(){
	    	
	    }
	 
	    /**
	     * Extractor Name
	     */
	    public String getExtractorName() {
	        return this.getClass().getName();
	    }
	    
	    /**
	     * ExtractorMAtches 
	     * @param feedUrl URL of the feed
	     * @return true if the url contains megavideo
	     */
	    public boolean extractorMatches(URL feedUrl) {

	    	Pattern pattern = Pattern.compile("https?://www\\.megavideo\\.com/[a-zA-Z_0-9&?=]*v=(.)*");
	       
		return pattern.matcher(feedUrl.toString()).matches();

	    }
	    
	    /**
	     * ContentURLContainer
	     * @param links Map with the links
	     * @param requestedQuality Requested Quality (With High, HD go first, other, HD go last)
	     */
	    public ContentURLContainer extractUrl(Map links, PreferredQuality requestedQuality) {
	       
	    	String videoLink ="";
			try {
			 // get link from default only if alternate doesn't exists
			 URL linkURL =(URL) (links.get("alternate")!=null?links.get("alternate"):links.get("default"));
					 
			 
			 // Get megavideoID from url
			 String megavideoID=getMegavideoId(linkURL.toString());
			
			 
			 //Launch HttpConnection for getting video Infor
			 String metaDataHtml=getResponseContent(new URL(baseInfoUri+megavideoID));
			 
			 // only get ROW element 
			 metaDataHtml= metaDataHtml.substring(metaDataHtml.indexOf("<ROW"),metaDataHtml.indexOf("</ROW>"));
			 
			 if(PreferredQuality.HIGH.equals(requestedQuality)){
	         
		        // HD GO FIRST
		         if(getAttribute(metaDataHtml,"hd_url")!=null){
		        	
		        	 videoLink= URLDecoder.decode(getAttribute(metaDataHtml,"hd_url")+"out.flv","UTF-8");
		         }
		         else if(getAttribute(metaDataHtml,"hd_k1")!=null &&
		        		 getAttribute(metaDataHtml,"hd_k2")!=null &&
		        		 getAttribute(metaDataHtml,"hd_un")!=null &&
		        		 getAttribute(metaDataHtml,"hd_s")!=null 
		        		 ){
		        	 videoLink=decrypt(getAttribute(metaDataHtml,"hd_k1"),
		        			 getAttribute(metaDataHtml,"hd_k2"),
		        			 getAttribute(metaDataHtml,"hd_un"),
		        			 getAttribute(metaDataHtml,"hd_s"));
		         }
		         else if(getAttribute(metaDataHtml,"downloadurl")!=null){
		        	 videoLink=URLDecoder.decode(getAttribute(metaDataHtml,"downloadurl")+"out.flv","UTF-8");
		         }
		         else if(getAttribute(metaDataHtml,"k1")!=null &&
		        		 getAttribute(metaDataHtml,"k2")!=null &&
		        		 getAttribute(metaDataHtml,"un")!=null &&
		        		 getAttribute(metaDataHtml,"s")!=null 
		        		 ){
		        	 videoLink=decrypt(getAttribute(metaDataHtml,"k1"),
		        			 getAttribute(metaDataHtml,"k2"),
		        			 getAttribute(metaDataHtml,"un"),
		        			 getAttribute(metaDataHtml,"s"));
		         }
			 }
		     else{
		    	 
		    	 	//HD go Last
		    	    if(getAttribute(metaDataHtml,"downloadurl")!=null){
			        	 videoLink=URLDecoder.decode(getAttribute(metaDataHtml,"downloadurl")+"out.flv","UTF-8");
			         }
		    	    else if(getAttribute(metaDataHtml,"k1")!=null &&
			        		 getAttribute(metaDataHtml,"k2")!=null &&
			        		 getAttribute(metaDataHtml,"un")!=null &&
			        		 getAttribute(metaDataHtml,"s")!=null 
			        		 ){
			        	 videoLink=decrypt(getAttribute(metaDataHtml,"k1"),
			        			 getAttribute(metaDataHtml,"k2"),
			        			 getAttribute(metaDataHtml,"un"),
			        			 getAttribute(metaDataHtml,"s"));
			         }
			         else if(getAttribute(metaDataHtml,"hd_url")!=null){
			        	
			        	 videoLink= URLDecoder.decode(getAttribute(metaDataHtml,"hd_url")+"out.flv","UTF-8");
			         }
			         else if(getAttribute(metaDataHtml,"hd_k1")!=null &&
			        		 getAttribute(metaDataHtml,"hd_k2")!=null &&
			        		 getAttribute(metaDataHtml,"hd_un")!=null &&
			        		 getAttribute(metaDataHtml,"hd_s")!=null 
			        		 ){
			        	 videoLink=decrypt(getAttribute(metaDataHtml,"hd_k1"),
			        			 getAttribute(metaDataHtml,"hd_k2"),
			        			 getAttribute(metaDataHtml,"hd_un"),
			        			 getAttribute(metaDataHtml,"hd_s"));
			         }
			        
		     }
	           
	         
	       
	        
			}
			catch(Exception e){
				e.printStackTrace();
			}
			
			//No Thumbnail obtained. Only URL
			ContentURLContainer container = new ContentURLContainer();
			
			container.setContentUrl(videoLink);
			container.setFileType(MediaFileType.VIDEO);
			return container;
	    }
	 
	    
	    /**
	     * getMegavideoId Get MegavideoID from url
	     * @param url The url
	     * @return MEgavideoID
	     */
	    public String getMegavideoId(String url){
	    	
	    	int start = url.indexOf("v=")+2;
	    	int end = url.indexOf("&",start);
	    	if(end < 0){
	    		end = url.length();
	    	}
	    	String idMEgavideo= url.substring(start,end);
	    	return idMEgavideo;
	    }
	    
	    /**
	     * Get an attribute value from html
	     * @param html Html String 
	     * @param attribute Attribute name	     * 
	     * @return attribute value
	     */
	    public String getAttribute(String html,String attribute){
	    	String value=null;
	    	int start = html.indexOf(" "+attribute+"=")+attribute.length()+2;
	    	if(start>=0){
	    		start  =  html.indexOf("\"",start)+1;
	    		int end = html.indexOf("\"",start);
	    		if(end >= 0){
	    			value=html.substring(start,end);
	    			if(value.trim().length()==0){
	    				value=null;
	    			}
	    		}
	    	}
	    	return value;
	    	
	    }
	    /**
	     * Decrypt de video link for megavideo
	     * @param key1 Key one
	     * @param key2 Key two
	     * @param codedString encripted string
	     * @param server Server where the video is hosted
	     * @return Decripted url
	     * @throws Exception 
	     */
	    public String decrypt(String key1,String key2, String codedString, String server) throws Exception{
			
			codedString = codedString.toUpperCase();
			int[] numbers = new int[codedString.length()*4];
			
			for (int i = 0; i < codedString.length(); i++) {
				String aux=Integer.toBinaryString(Integer.parseInt(String.valueOf(codedString.charAt(i)),16));
				while(aux.length()<4){
					aux="0"+aux;
				}
				numbers[i*4]=aux.charAt(0)-48;
				numbers[(i*4)+1]=aux.charAt(1)-48;
				numbers[(i*4)+2]=aux.charAt(2)-48;
				numbers[(i*4)+3]=aux.charAt(3)-48;
				
			}
			String url = null;
			int k1 = Integer.parseInt(key1);
			int k2 = Integer.parseInt(key2);
			int[] iv=	new int[384];	
			 for( int i = 0;i<384;i++ ){
		        k1 = (k1 * 11 + 77213) % 81371;
		        k2 = (k2 * 17 + 92717) % 192811;
		        iv[i] = (k1 + k2) % 128;
		      
			 }
			 int a,b,c;
			 for(int  i = 256;i >= 0;i--){ 
		        a = iv[i];
		        b = i % 128;
		        c = numbers[a ];
		       
		       
		        numbers[a] = numbers[b];
		        numbers[b ] = c;
		      
			 }
			 
			 
			  for(int i=0; i < 128;i++){
				 
				  numbers[i]=numbers[i] ^ (iv[i + 256] & 1);
			  }
			 
	          StringBuffer decripted= new StringBuffer();
	          for(int i=0; i<numbers.length; i=i+4)
	          {
	            
	        	  int aux=(numbers[i]*8+numbers[i+1]*4+numbers[i+2]*2+numbers[i+3]);
	        	               
	        	  decripted.append(String.format("%1x", aux));
	          }
	        
	          url = "http://www" + server + ".megavideo.com/files/" +decripted.toString().toLowerCase()  + "/out.flv";    
			return url;
		}
	    
	    /**
	     * Launch an httpConnectino and returns response Body
	     * @param url Url to connect
	     * @return Response Body
	     * @throws Exception
	     */
	    public static String getResponseContent(URL url) throws Exception {
	        String responseBody = null;
	        HttpParams params = new BasicHttpParams();
	        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
	        HttpProtocolParams.setContentCharset(params, "UTF-8");
	       

	        BasicHttpProcessor httpproc = new BasicHttpProcessor();
	        
	        httpproc.addInterceptor(new RequestContent());
	        httpproc.addInterceptor(new RequestTargetHost()); 
	        
	        HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
	        
	        HttpContext context = new BasicHttpContext(null);
	        HttpHost host = new HttpHost(url.getHost(), url.getPort() != -1 ? url.getPort() : 80);

	        DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
	   

	        context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
	        context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, host);

	        try {
	            
	            
	           
	                if (!conn.isOpen()) {
	                    Socket socket = new Socket(host.getHostName(), host.getPort());
	                    conn.bind(socket, params);
	                }
	                BasicHttpRequest request = new BasicHttpRequest("GET", url.toString());
	               
	                
	                request.setParams(params);
	                httpexecutor.preProcess(request, httpproc, context);
	                HttpResponse response = httpexecutor.execute(request, conn, context);
	                response.setParams(params);
	                httpexecutor.postProcess(response, httpproc, context);
	                
	              
	                responseBody = EntityUtils.toString(response.getEntity());
	               
	               
	                    conn.close();
	               
	                    
	        } finally {
	            conn.close();
	        }
	        return responseBody;
	    }
	

}

