package br.com.millennium.api;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.lang.reflect.Type;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.PasswordAuthentication;
import java.net.URL;
import java.util.zip.Inflater;
import java.util.zip.InflaterInputStream;

import com.alibaba.fastjson.JSON;

public class HTTPClient {
	 
	private char[] cbuf;
	private StringBuffer response;
	
	private String host="localhost";
	private int    port=888;
	private String api_base;
	
	public HTTPClient(final String host,final String user,final String pass){
		setHost(host,this.port);
		setAuthenticationInfo(user,pass);
	}
	
	public HTTPClient(final String host,final int port,final String user,final String pass){
		setHost(host,port);
		setAuthenticationInfo(user,pass);
	}
	
	private void refreshApiBase(){
		api_base = "http://"+host+":"+port+"/api/";
	}
	
	public void setHost(String host,int port){
		this.host = host;
		this.port = port;
		refreshApiBase();
	}
	
	public void setAuthenticationInfo(final String user,final String pass){
		Authenticator.setDefault(new Authenticator() {							
	        @Override
	        protected PasswordAuthentication getPasswordAuthentication() {	        	        		      
	        	if (this.getRequestingHost().equalsIgnoreCase("millennium.iwise.com.br"))
	        	{
	            return new PasswordAuthentication(
	            		user,
	            		pass.toCharArray() ) ;
	        	}
	        	else
	        		return null;
	        }
	    });		
	}
	
	private String convertStreamToString(InputStream stream,int expectedLength) throws IOException
	{
		//alloc buffers	
		if (response==null) response = new StringBuffer();
		if (cbuf==null) cbuf = new char[1024*8];
		
		InputStreamReader in = new InputStreamReader(stream,"UTF-8");
					
		int br,tbr=0;		
		
		if(expectedLength>0) response.ensureCapacity(expectedLength); 
		response.delete(0, response.length());
		while ((br = in.read(cbuf))>0) {
			response.append(cbuf);
			tbr += br;
		}
		in.close(); 										
		
		return response.substring(0,tbr);
	}
	
	public final <T> T Call(String verb,final String name,final Object args,final Class<T> clazz) throws IOException{
		String url = api_base+name;
		
		URL obj = new URL(url);
		
		HttpURLConnection con = (HttpURLConnection) obj.openConnection();
							
		// optional default is GET			
		con.setRequestMethod(verb);
 
		//add request header
		con.setRequestProperty("Content-Type", "application/json");
		con.setRequestProperty("Accept", "application/json");
		con.setRequestProperty("Accept-Encoding", "deflate");
		con.setRequestProperty("DataServiceVersion", "3.0");
		con.setAllowUserInteraction(false);
		con.setUseCaches(false);
		
		if (args!=null)
		{
			con.setDoOutput(true);
			
			OutputStream out = con.getOutputStream();		
			out.write(JSON.toJSONBytes(args));
			out.close();
		}
		
		int responseCode = con.getResponseCode();		 										
						
		if (responseCode<400)		
           return JSON.parseObject(convertStreamToString(new InflaterInputStream(con.getInputStream(),new Inflater(true)),con.getContentLength()), (Type) clazz);
		else
		{
		   InputStream err = con.getErrorStream();
		   if (err==null)
			   throw new IOException("Error calling service "+name+": HTTP error "+responseCode); //let the default error raise
		   else
	           throw new IOException("Error calling service "+name+": "+convertStreamToString(err,con.getContentLength()));
		}
	}	
	
	public final <T> T Get(final String name,final Object args,final Class<T> clazz) throws IOException{
		return Call("GET",name,args,clazz);
	}	
	
	public final <T> T Post(final String name,final Object args,final Class<T> clazz) throws IOException{
		return Call("POST",name,args,clazz);  
	}	
}
