package com.bradmcevoy.http.http11;

import com.bradmcevoy.http.GetableResource;
import com.bradmcevoy.http.Range;
import com.bradmcevoy.http.Request;
import com.bradmcevoy.http.Response;
import com.bradmcevoy.http.exceptions.BadRequestException;
import com.bradmcevoy.http.exceptions.NotAuthorizedException;
import com.bradmcevoy.io.StreamUtils;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author brad
 */
public class PartialGetHelper {

	private static final Logger log = LoggerFactory.getLogger(PartialGetHelper.class);
	private final Http11ResponseHandler responseHandler;
	private int maxMemorySize = 100000;

	public PartialGetHelper(Http11ResponseHandler responseHandler) {
		this.responseHandler = responseHandler;
	}

	public List<Range> getRanges(String rangeHeader) {
		if (rangeHeader == null || rangeHeader.length() == 0) {
			log.trace("getRanges: no range header");
			return null;
		}
		if (rangeHeader.startsWith("bytes=")) {
			rangeHeader = rangeHeader.substring(6);
			String[] arr = rangeHeader.split(",");
			List<Range> list = new ArrayList<Range>();
			for (String s : arr) {
				final Matcher matcher = Pattern.compile("\\s*(\\d+)-(\\d+)").matcher(s);
				if (matcher.matches()) {
					Range r = new Range(Long.parseLong(matcher.group(1)), Long.parseLong(matcher.group(2)));
					list.add(r);
				}
			}
			if (log.isTraceEnabled()) {
				log.trace("getRanges: header: " + rangeHeader + " parsed ranges: " + list.size());
			}
			return list;

		} else {
			return null;
		}
	}

	public void sendPartialContent(GetableResource resource, Request request, Response response, List<Range> ranges, Map<String, String> params) throws NotAuthorizedException, BadRequestException, IOException {
		log.trace("sendPartialContent");
		if (ranges.size() == 1) {
			log.trace("partial get, single range");
			Range r = ranges.get(0);
			responseHandler.respondPartialContent(resource, response, request, params, r);
		} else {
			log.trace("partial get, multiple ranges");
			File temp = File.createTempFile("milton_partial_get", null);
			FileOutputStream fout = null;
			try {
				fout = new FileOutputStream(temp);
				BufferedOutputStream bufOut = new BufferedOutputStream(fout);
				resource.sendContent(bufOut, null, params, request.getContentTypeHeader());
				bufOut.flush();
				fout.flush();
			} finally {
				StreamUtils.close(fout);
			}
			OutputStream responseOut = response.getOutputStream();
			FileInputStream fin = null;
			try {
				System.out.println("temp file length: " + temp.length());
				fin = new FileInputStream(temp);
				writeRanges(fin, ranges, responseOut);
			} finally {
				StreamUtils.close(fin);
			}			
		}
	}

	public static void writeRanges(InputStream in, List<Range> ranges, OutputStream responseOut) throws IOException {
		try {
			InputStream bufIn = in; //new BufferedInputStream(in);
			long pos = 0;
			for (Range r : ranges) {
				long skip = r.getStart() - pos;
				bufIn.skip(skip);
				long length = r.getFinish() - r.getStart();
				sendBytes(bufIn, responseOut, length);
				pos = r.getFinish();
			}
		} finally {
			StreamUtils.close(in);
		}
	}

	public static void writeRange(InputStream in, Range r, OutputStream responseOut) throws IOException {
		long skip = r.getStart();
		in.skip(skip);
		long length = r.getFinish() - r.getStart();
		sendBytes(in, responseOut, length);
	}

	public int getMaxMemorySize() {
		return maxMemorySize;
	}

	public void setMaxMemorySize(int maxMemorySize) {
		this.maxMemorySize = maxMemorySize;
	}

	public static void sendBytes(InputStream in, OutputStream out, long length) throws IOException {
		log.trace("sendBytes: " + length);
		long numRead = 0;
		byte[] b = new byte[1024];
		while (numRead < length) {
			long remainingBytes = length - numRead;
			int maxLength = remainingBytes > 1024 ? 1024 : (int) remainingBytes;
			int s = in.read(b, 0, maxLength);
			if( s < 0 ) {
				break;
			}
			numRead += s;
			out.write(b, 0, s);
		}

	}
}

@@ -2829,70 +2829,8 @@
 y %7B%0A
-%09%09%09%09System.out.println(%22temp file length: %22 + temp.length());%0A
 %09%09%09%09

remove system.out messages