

//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
//_/_/
//_/_/  This file is part of CMSDK version 2.0.0.170915_Beta4 (15 September 2017)
//_/_/  
//_/_/  developed by
//_/_/  
//_/_/  Communicative Machines Ltd. 
//_/_/    http://cmlabs.com/
//_/_/  Copyright (c) 2017
//_/_/  
//_/_/  in collaboration with 
//_/_/  
//_/_/  Icelandic Institute for Intelligent Machines ses
//_/_/    Menntavegur 1
//_/_/    101 Reykjavik
//_/_/    ICELAND
//_/_/    http://www.iiim.is/
//_/_/
//_/_/  and is released under the following
//_/_/  
//_/_/  EXTENDED BSD License
//_/_/
//_/_/  Redistribution and use in source and binary forms, with or without
//_/_/  modification, is permitted provided that the following conditions 
//_/_/  are met:
//_/_/
//_/_/  - Redistributions of source code must retain the above copyright 
//_/_/    and collaboration notice, this list of conditions and the following 
//_/_/    disclaimer.
//_/_/
//_/_/  - Redistributions in binary form must reproduce the above copyright 
//_/_/    notice, this list of conditions and the following disclaimer in the 
//_/_/    documentation and/or other materials provided with the distribution.
//_/_/
//_/_/  - Neither the name of its copyright holders nor the names of its 
//_/_/    contributors may be used to endorse or promote products derived from 
//_/_/    this software without specific prior written permission.
//_/_/
//_/_/  - CADIA Clause: The license granted in and to the software under this 
//_/_/    agreement is a limited-use license.Β The software may not be used in 
//_/_/    furtherance of: (i) intentionally causing bodily injury or severe 
//_/_/    emotional harm to any person; (ii) invading the personal privacy or 
//_/_/    violating the human rights of any person; or (iii) committing or 
//_/_/    preparing for any act of war. 
//_/_/
//_/_/  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
//_/_/  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
//_/_/  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
//_/_/  PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
//_/_/  OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
//_/_/  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
//_/_/  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
//_/_/  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
//_/_/  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
//_/_/  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
//_/_/  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//_/_/
//_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/
#include "HTML.h"

namespace cmlabs {
namespace html {

std::string DecodeHTML(std::string str) {

	size_t p = 0, c;
	while ((p = str.find("+", p)) != std::string::npos) {
		str.replace(p, 1, 1, ' ');
	}

	char ch;
	p = 0;
	while ((p = str.find("&", p)) != std::string::npos) {
		if ( (c = str.find(";", p)) != std::string::npos ) {
			// Check string between p - c
			if (str[p+1] == '#') {
				if (str[p+2] == 'x')
					ch = (char) strtol(str.substr(p+3, c-p-3).c_str(), NULL, 16);
				else
					ch = (char) strtol(str.substr(p+2, c-p-2).c_str(), NULL, 10);
				if (ch == 0)
					ch = ' ';
				str.replace(p, c-p+1, 1, ch);
			}
			else {
				str.replace(p, c-p+1, 1, (char)html::HTML2Char(str.substr(p+1, c-p-1).c_str()));
			}
		}
		p++;
	}

	p = 0;
	while ((p = str.find("%", p)) != std::string::npos) {
		ch = (char) strtol(str.substr(p+1, 2).c_str(), NULL, 16);
		if (ch == 0)
			ch = ' ';
		str.replace(p, 3, 1, ch);
	}

	return str;
}

std::string EncodeHTML(std::string str) {
	if (str.size() == 0)
		return str;
	std::string result = str;
	char c;
	char* tmp = (char*)malloc(20);

	for (uint32 n=0; n<result.size(); n++) {
		switch(c = result[n]) {
			case '\n':
				result.replace(n, 1, "<br>\n");
				n+=4;
				break;
			case '\r':
				result.replace(n, 1, "");
				n-=1;
				break;
			case '\t':
				result.replace(n, 1, "&nbsp;&nbsp;&nbsp;");
				n+=17;
				break;
			default:
				if ( (c < 32) || (c > 122) ||
					( (c > 90) && (c < 97) ) ||
					( (c > 57) && (c < 65) ) ||
					( (c > 33) && (c < 48) ) ) {
					snprintf(tmp, 20, "&#x%x;", (int) c & 0xFF);
					result.replace(n, 1, tmp);
					n+=(uint32)strlen(tmp)-1;
				}
				break;
		}
	}

	free((char*)tmp);

	return result;
}

unsigned char HTML2Char(const char* str) {
	if (strcmp(str, "amp") == 0)
		return '&';
	else if (strcmp(str, "lt") == 0)
		return '<';
	else if (strcmp(str, "gt") == 0)
		return '>';
	else if (strcmp(str, "quot") == 0)
		return '"';
	else if (strcmp(str, "apos") == 0)
		return '\'';
	else if (strcmp(str, "lsquo") == 0)
		return '';
	else if (strcmp(str, "rsquo") == 0)
		return '';
	else if (strcmp(str, "sbquo") == 0)
		return '';
	else if (strcmp(str, "ldquo") == 0)
		return '';
	else if (strcmp(str, "rdquo") == 0)
		return '';
	else if (strcmp(str, "bdquo") == 0)
		return '';
	else if (strcmp(str, "dagger") == 0)
		return '';
	else if (strcmp(str, "Dagger") == 0)
		return '';
	else if (strcmp(str, "permil") == 0)
		return '';
	else if (strcmp(str, "lsaquo") == 0)
		return '';
	else if (strcmp(str, "rsaquo") == 0)
		return '';
	else if (strcmp(str, "trade") == 0)
		return '';
	else
		return ' ';
}


bool GetMimeType(char* dest, const char* filename, uint32 maxsize) {
	bool isBinary;
	return GetMimeType(dest, filename, maxsize, isBinary);
}

bool GetMimeType(char* dest, const char* filename, uint32 maxsize, bool &isBinary) {

	isBinary = true;
	if (!filename && (maxsize < 3))
		return false;

	if (utils::TextEndsWith(filename, ".bmp"))
		return (utils::strcpyavail(dest, "image/bmp", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".gif"))
		return (utils::strcpyavail(dest, "image/gif", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".jpg"))
		return (utils::strcpyavail(dest, "image/jpeg", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".png"))
		return (utils::strcpyavail(dest, "image/png", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".svg"))
		return (utils::strcpyavail(dest, "image/svg+xml", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".tif"))
		return (utils::strcpyavail(dest, "image/tiff", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".ico"))
		return (utils::strcpyavail(dest, "image/x-icon", maxsize, false) != 0);

	else if ( (utils::TextEndsWith(filename, ".html")) || (utils::TextEndsWith(filename, ".htm")) ) {
		isBinary = false;
		return (utils::strcpyavail(dest, "text/html", maxsize, false) != 0);
	}
	else if (utils::TextEndsWith(filename, ".css")) {
		isBinary = false;
		return (utils::strcpyavail(dest, "text/css", maxsize, false) != 0);
	}
	else if (utils::TextEndsWith(filename, ".js")) {
		isBinary = false;
		return (utils::strcpyavail(dest, "text/javascript", maxsize, false) != 0);
	}
	else if (utils::TextEndsWith(filename, ".json")) { // should ideally be 'application/json', but IE <= 8 doesn't work :-)
		isBinary = false;
		return (utils::strcpyavail(dest, "application/json", maxsize, false) != 0);
		//return (utils::strcpyavail(dest, "text/html", maxsize, false) != 0);
	}
	else if (utils::TextEndsWith(filename, ".xml")) {
		isBinary = false;
		return (utils::strcpyavail(dest, "text/xml", maxsize, false) != 0);
	}
	else if (utils::TextEndsWith(filename, ".txt")) {
		isBinary = false;
		return (utils::strcpyavail(dest, "text/plain", maxsize, false) != 0);
	}
	else if (utils::TextEndsWith(filename, ".log")) {
		isBinary = false;
		return (utils::strcpyavail(dest, "text/plain", maxsize, false) != 0);
	}
	else if (utils::TextEndsWith(filename, ".bin"))
		return (utils::strcpyavail(dest, "application/octet-stream", maxsize, false) != 0);

	else if ( (utils::TextEndsWith(filename, ".mp3"))
		|| (utils::TextEndsWith(filename, ".mpg")) 
		|| (utils::TextEndsWith(filename, ".mpa")) )
		return (utils::strcpyavail(dest, "audio/mpeg", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".wav"))
		return (utils::strcpyavail(dest, "audio/x-wav", maxsize, false) != 0);
	else if ( (utils::TextEndsWith(filename, ".mpeg"))
		|| (utils::TextEndsWith(filename, ".mpe")) 
		|| (utils::TextEndsWith(filename, ".mp2")) 
		|| (utils::TextEndsWith(filename, ".mpv2")) )
		return (utils::strcpyavail(dest, "video/mpeg", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".mp4"))
		return (utils::strcpyavail(dest, "video/mp4", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".avi"))
		return (utils::strcpyavail(dest, "video/msvideo", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".h263"))
		return (utils::strcpyavail(dest, "video/h263", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".h264"))
		return (utils::strcpyavail(dest, "video/h264", maxsize, false) != 0);
	else if ( (utils::TextEndsWith(filename, ".qt")) || (utils::TextEndsWith(filename, ".mov")) )
		return (utils::strcpyavail(dest, "video/quicktime", maxsize, false) != 0);

	else if (utils::TextEndsWith(filename, ".zip"))
		return (utils::strcpyavail(dest, "application/zip", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".gz"))
		return (utils::strcpyavail(dest, "application/x-gzip", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".tar"))
		return (utils::strcpyavail(dest, "application/x-tar", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".pdf"))
		return (utils::strcpyavail(dest, "application/pdf", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".doc"))
		return (utils::strcpyavail(dest, "application/msword", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".xls"))
		return (utils::strcpyavail(dest, "application/vnd.ms-excel", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".ppt"))
		return (utils::strcpyavail(dest, "application/vnd.ms-powerpoint", maxsize, false) != 0);

	else if (utils::TextEndsWith(filename, ".eot"))
		return (utils::strcpyavail(dest, "application/vnd.ms-fontobject", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".woff"))
		return (utils::strcpyavail(dest, "application/font-woff", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".woff2"))
		return (utils::strcpyavail(dest, "application/font-woff2", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".ttf"))
		return (utils::strcpyavail(dest, "application/x-font-truetype", maxsize, false) != 0);
	else if (utils::TextEndsWith(filename, ".otf"))
		return (utils::strcpyavail(dest, "application/x-font-opentype", maxsize, false) != 0);

	else
		return false;
}


std::string GetUsernameFromURL(std::string url) {
	std::string auth = GetAuthenticationFromURL(url);
	if (!auth.size())
		return "";

	size_t colon = url.find(':');
	if (colon == std::string::npos)
		return auth;
	else
		return url.substr(0, colon);
}

std::string GetPasswordFromURL(std::string url) {
	std::string auth = GetAuthenticationFromURL(url);
	if (!auth.size())
		return "";

	size_t colon = url.find(':');
	if (colon == std::string::npos)
		return "";
	else
		return url.substr(colon+1);
}

std::string GetAuthenticationFromURL(std::string url) {
	size_t start = url.find("//");
	if (start == std::string::npos)
		return "";

	size_t offset = url.find("@");
	if (offset == std::string::npos)
		return "";

	return url.substr(start, offset-start);
}

std::string GetHostFromURL(std::string url) {
	size_t offset = url.find("@");
	if (offset == std::string::npos) {
		offset = url.find("//");
		if (offset == std::string::npos)
			return "";
		else
			offset += 2;
	}
	else
		offset++;

	size_t end = url.find(':', offset);
	if (end != std::string::npos)
		return url.substr(offset, end-offset);

	end = url.find('/', offset);
	if (end != std::string::npos)
		return url.substr(offset, end-offset);

	return url.substr(offset);
}

uint16 GetPortFromURL(std::string url) {
	size_t offset = url.find("@");
	if (offset == std::string::npos) {
		offset = url.find("//");
		if (offset == std::string::npos)
			return 0;
		else
			offset += 2;
	}
	else
		offset++;

	size_t colon = url.find(':', offset);
	if (colon == std::string::npos)
		return 0;

	return (uint16) utils::Ascii2Uint32(url.substr(colon+1).c_str());
}

std::string GetProtocolFromURL(std::string url) {
	if (url.find("http:") == 0)
		return "http";
	else if (url.find("https:") == 0)
		return "https";
	else if (url.find("ftp:") == 0)
		return "ftp";

	size_t offset = url.find("//");
	if (offset == std::string::npos)
		return "";

	return url.substr(0, offset);
}

std::string GetURIFromURL(std::string url) {
	size_t offset = url.find("//");
	if (offset == std::string::npos)
		return "";

	offset += 2;

	size_t end = url.find('/', offset);
	if (end != std::string::npos)
		return url.substr(end);
	else
		return "/";
}

} // namespace html
} // namespace cmlabs


