/**
 * File:   HTTPClient.cpp
 * Author: Alexander Ksenofontov <aksenofo@yahoo.ru>
 *
 * Created on August 15, 2016, 14:13 PM
 */

#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>

#include "tohaux.h"
#include "HTTPClient.h"

using boost::asio::ip::tcp;

void sync_file_with_server(message_listener* ml, const std::string& url, const std::string& dest) {
    boost::filesystem::path p(dest);
    create_directory_recursively(p.parent_path());

    // create dest file
    std::ofstream os;
    os.exceptions(std::ofstream::failbit | std::ofstream::badbit);
    os.open(dest.c_str(), std::ofstream::binary);
    sync_file_with_server(ml, url, os);
}

// Download file from HTTP Server and create directory recursively
void sync_file_with_server(message_listener* ml, const std::string& url, std::ostream& os) {
    boost::asio::io_service io_service;
    tcp::resolver resolver(io_service);
    url_parser url_parsed(url);
    tcp::resolver::query query(url_parsed.host_, url_parsed.port_);
    tcp::resolver::iterator endpoint_iterator = resolver.resolve(query);
    if(ml->aborted())
		throw message_listener::exception();

    tcp::socket socket(io_service);
    boost::asio::connect(socket, endpoint_iterator);

    boost::asio::streambuf request;
    std::ostream request_stream(&request);
    request_stream << "GET " << url_path_encode(url_parsed.path_) 
	                     << url_path_encode(url_parsed.file_) 
			     << url_path_encode(url_parsed.parameter_) 
			     << " HTTP/1.0\r\n";
    request_stream << "Accept: */*\r\n";
    request_stream << "Host: " << url_parsed.host_ << ":" << url_parsed.port_ << "\r\n";
    request_stream << "Connection: close\r\n\r\n";

    boost::asio::write(socket, request);
    boost::asio::streambuf response;
    boost::asio::read_until(socket, response, "\r\n");

    std::istream response_stream(&response);
    std::string http_version;
    response_stream >> http_version;
    unsigned int status_code;
    response_stream >> status_code;
    std::string status_message;
    std::getline(response_stream, status_message);

    if (ml->aborted())
		throw message_listener::exception();

    if (!response_stream || http_version.substr(0, 5) != "HTTP/")
		throw std::runtime_error("Invalid response(It's not HTTP)");

    if (status_code != 200)
		throw std::runtime_error("Response returned with status code:" + status_code);

    boost::asio::read_until(socket, response, "\r\n\r\n");
    response.consume(response.size());
    boost::system::error_code error;

    while (uint64_t len = boost::asio::read(socket, response, boost::asio::transfer_at_least(1), error)) {
	os << &response;

	if (ml->aborted())
	    throw message_listener::exception();

//	ml->fill([&](http_info& hi) {
//	    hi.total_ += len;
//	    hi.per_file_ = len;
//	});
    }

    if (error != boost::asio::error::eof)
		throw boost::system::system_error(error);
}
