
import HttpLibrary.*;


import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Vector;



class ServeConnection extends Thread {
	private Socket socket;
	
	private InputStream in;
	private OutputStream out;
	
	public ServeConnection(Socket s) throws IOException {
        socket = s;
        in = socket.getInputStream();
        out = socket.getOutputStream();
        start();
	}
	
	
	public void run() {
		HttpResponse response;
		
		try {
			HttpRequest req = HttpProtocol.readRequest(in);
			response = getResponse(req);
			
			
		} catch (IOException e) {
			response = new HttpResponse(HttpStatus.FORBIDDEN, new ByteArrayInputStream(("error").getBytes()));
		}
		
		try {
			HttpProtocol.writeResponse(response, out);
			socket.close();
			
			System.out.println("Response sent "+response.getStatus());
		} catch (IOException e) {
			
			System.out.println("Response unsucessful");			
		}
	}
	
	private HttpResponse getResponse(HttpRequest req) {
		File file = new File(MyHttpServer.root + File.separator + req.getPath());
		if(file.isDirectory()){
			return new HttpResponse(HttpStatus.OK, getDirectoryListing(req, file));
		}
		
		System.out.println("Got request - file: "+file.getAbsolutePath());
		
		try {
			FileInputStream is = new FileInputStream(file);
			return new HttpResponse(HttpStatus.OK, is);
			
		}
		catch (FileNotFoundException e) {
			return new HttpResponse(HttpStatus.NOT_FOUND, new ByteArrayInputStream(("404 Not Found").getBytes()));
		}
		
	}



	class FileItem {
		public String name;
		public long lastMod;
		public long size;
		public String strLastMod(){
			return new Date(lastMod).toGMTString();
		}
		public String strSize(){
			if(size>1000) return Math.round(size/1000) + "kB";
			return size + "B";
		}
		public FileItem(File dir, String name){
			this.name = name;
			File fileDir = new File(dir.getAbsolutePath() + File.separator + name);
			this.lastMod = fileDir.lastModified(); 
			this.size = fileDir.length();
		}
	}
	class NameComparator implements Comparator<FileItem> {
		private int c=1; 
		public NameComparator(int c) {this.c = c;}
		@Override
		public int compare(FileItem o1, FileItem o2) {
			return c*o1.name.compareTo(o2.name);
		}
	}
	class LastModComparator implements Comparator<FileItem> {
		private int c=1; 
		public LastModComparator(int c) {this.c = c;}
		@Override
		public int compare(FileItem o1, FileItem o2) {
			return c* new Long(o1.lastMod).compareTo(o2.lastMod);
		}
	}
	class SizeComparator implements Comparator<FileItem> {
		private int c=1; 
		public SizeComparator(int c) {this.c = c;}
		@Override
		public int compare(FileItem o1, FileItem o2) {
			return c* new Long(o1.size).compareTo(o2.size);
		}
	}

	
	public String format(String s, int col){
		for(int x=s.length();x<=col;x++) s+=" ";
		return s;
	}

	private InputStream getDirectoryListing(HttpRequest req, File file) {
		String html = MyHttpServer.dirTemplate;
		
		html = html.replaceAll("\\{\\{PATH\\}\\}", req.getPath());
		
		//sorting
		List<FileItem> vectorSouboru = new Vector<FileItem>();
		for(String f : file.list()){
			vectorSouboru.add(new FileItem(file, f));
		}
		
		
		int nameSort = 1;
		int modifiedSort = 0;
		int sizeSort = 0;
		
		if(req.getSortProperty() == SortProperty.NAME){
			nameSort = req.getSortType() == SortType.ASC ? 1 : -1;
			modifiedSort = 1;
			sizeSort = 1;
			Collections.sort(vectorSouboru, new NameComparator(-nameSort));
		}
		else if(req.getSortProperty() == SortProperty.MODIFIED){
			nameSort = 1;
			modifiedSort = req.getSortType() == SortType.ASC ? 1 : -1;
			sizeSort = 1;
			Collections.sort(vectorSouboru, new LastModComparator(modifiedSort));
		}
		else if(req.getSortProperty() == SortProperty.SIZE){
			nameSort = 1;
			modifiedSort = 1;
			sizeSort = req.getSortType() == SortType.ASC ? 1 : -1;
			Collections.sort(vectorSouboru, new SizeComparator(sizeSort));
		}

		html = html.replaceAll("\\{\\{NAME_SORT_TYPE\\}\\}", ""+(nameSort >0 ? "D" : "A"));
		html = html.replaceAll("\\{\\{MODIFIED_SORT_TYPE\\}\\}", ""+(modifiedSort>0 ? "D" : "A"));
		html = html.replaceAll("\\{\\{SIZE_SORT_TYPE\\}\\}", ""+(sizeSort>0 ? "D" : "A"));
		
		
		
		//formating
		int dateColumn = 28+4;
		int nameColumn = 21;
		for(FileItem f : vectorSouboru){
			nameColumn = Math.max(nameColumn, f.name.length());
		}
		nameColumn += 8;
		
		String htmlList = "";
		
		FileItem xx = new FileItem(file, "..");
		
		htmlList += "<a href='..'>[..] Parent Directory</a>"+format("", nameColumn-21) + format(xx.strLastMod(), dateColumn) + "-\n";
		
		for(FileItem f : vectorSouboru){
			String path = req.getPath()+ (req.getPath().substring(req.getPath().length()-1).equals("/") ? "" : "/");
			
			if(new File(file.getAbsoluteFile() + path+f.name).isDirectory())
				htmlList += "<a href='"+path+f.name+"'>[DIR] "+f.name+"</a>"+format("", nameColumn-f.name.length()-6) 
				+ format(f.strLastMod(), dateColumn) + "-\n";
			else
				htmlList += "<a href='"+path+f.name+"'>"+f.name+"</a>"+format("", nameColumn-f.name.length()) 
				+ format(f.strLastMod(), dateColumn) + f.strSize()+"\n";
		}
		
		html = html.replaceAll("\\{\\{FILE_LIST\\}\\}", htmlList);
		html = html.replaceAll("\\{\\{NAME_PADDING\\}\\}", format("", nameColumn-4));
		html = html.replaceAll("\\{\\{MODIFIED_PADDING\\}\\}", format("", dateColumn-13));
		
		
		return new ByteArrayInputStream((html).getBytes());
	}
	
	
	

	


}

