package com.eitima.HTTPServer;

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.net.Socket;

/**
 * Thread to handle each query concurrently.
 * @author Eitima (Zexi Huang)
 * @version 1.0 Oct 16, 2016
 */
public class ServerThread extends Thread
{
	Socket client;
	public ServerThread (Socket connectionSocket)
	{
		client=connectionSocket;
	}
	
	/**
	 * Overrided version of run for thread.
	 */
	@Override
	public void run()
	{
		//... 
		try
		{
			BufferedReader inFromClient=new BufferedReader(new InputStreamReader(client.getInputStream()));
			client.setSoTimeout(60);//Set timeout to 60s.
			
			String method="";
			String queryURL="";
			
			int state=0;
			
			while(true)
			{
				char nextChar=(char)inFromClient.read();
				boolean isSpace=Character.isWhitespace(nextChar);
				
				switch(state)
				{
					case 0://Skip invalid whitespaces before the method.
						if(isSpace)
							continue;
						else
							state=1;
					case 1://Read the method.
						if(isSpace)
						{
							state=2;
							continue;
						}
						else
						{	
							method=method+nextChar;
							continue;
						}
					case 2://Skip invalid whitespaces between method and URL.
						if(isSpace)
							continue;
						else
							state=3;
					case 3://Read URL.
						if(isSpace)
							break;
						else
						{
							queryURL=queryURL+nextChar;
							continue;
						}	
				}
				break;		
			}
			String head=getHead(queryURL);
			OutputStream outFromServer=client.getOutputStream();
			byte[] data=null;
			//Generate the response message.
			while(true)
			{
				try
				{
					if(inFromClient.read()<0)
					break;
				}
				catch(InterruptedIOException e) 
				{
					data=getFileByte("sources"+queryURL);
				}
				if(data!=null&&head!=null)//Object requested existed and legal to be transfered.
				{
					outFromServer.write(head.getBytes("utf-8"));
					outFromServer.write(data);
					outFromServer.close();
					break;
				}
				
				
			}
		} catch (IOException e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * Generate the head of the response message according to the filetype specified by query URL.
	 * @param queryURL
	 * @return head of response message
	 */
	public String getHead(String queryURL)
	{
		String filename="";
		int index=queryURL.lastIndexOf("/");
		filename=queryURL.substring(index+1);
		String[] filetypes=filename.split("\\.");
		String filetype=filetypes[filetypes.length-1];
		if(filetype.equals("html"))
		{
			return "HTTP/1.0 200 OK\n"+"Content-Type:text/html\n" + "Server:myserver\n" + "\n";
		}
		else if(filetype.equals("jpg")||filetype.equals("gif")||filetype.equals("png"))
		{
			return "HTTP/1.0 200 OK\n"+"Content-Type:image/jpeg\n" + "Server:myserver\n" + "\n";
		}
		else if(filetype.equals("ico"))
		{
			return "HTTP/1.0 200 OK\n"+"Content-Type:image/x-icon\n" + "Server:myserver\n" + "\n";
		}
		else if(filetype.equals("css"))
		{
			return "HTTP/1.0 200 OK\n"+"Content-Type:text/css\n" + "Server:myserver\n" + "\n";
		}
		else if(filetype.equals("js"))
		{
			return "HTTP/1.0 200 OK\n"+"Content-Type:application/x-javascript\n" + "Server:myserver\n" + "\n";
		}
		else if(filetype.equals("pdf"))
		{
			return "HTTP/1.0 200 OK\n"+"Content-Type:application/pdf\n" + "Server:myserver\n" + "\n";
		}
		else return null;
	}
	
	/**
	 * Return the file specified by filename by bytes.
	 * @param filename
	 * @return bytes of file
	 * @throws IOException
	 */
	public byte[] getFileByte(String filename) throws IOException
	{
		ByteArrayOutputStream byteArrayOutputStream=new ByteArrayOutputStream();
		File file=new File(filename);
		FileInputStream fileInputStream=new FileInputStream(file);
		byte[] b=new byte[1024];
		int read;
		while((read=fileInputStream.read(b))!=-1)
		{
			byteArrayOutputStream.write(b,0,read);
		}
		fileInputStream.close();
		byteArrayOutputStream.close();
		return byteArrayOutputStream.toByteArray();
	}
}

