module yamalib.log.netreport;

pragma(lib, "ws2_32.lib ");
private import std.string; // replace, toString
private import std.socket;
private import std.uri;

private import yamalib.auxil.properties;
private import yamalib.util.systeminfo;

/** リクエストを送るフォームの表現 */
interface ReportForm {
	/// 書き込む全てのKeyIDとデータのマップ
	char[][char[]] getData();
	/// HTTP リクエストの取得
	char[] getHTTPReq();

	/// HTTP リクエストの取得
	char[] getHTTPReqProxy();

	/// 送信先ホスト名の取得
	char[] getHostName();
}

/** DOBBS用フォーム定義 */
class ReportFormDoBBS : ReportForm {

	/// 送信先ホスト名の取得
	char[] getHostName() {
		return cast(char[]) HOST_VAL;
	}
	/// 全データ取得
	char[][char[]] getData() {
		return m_data;
	}
	/// メインメッセージをセット
	void setMessage(char[] msg) {
		m_data["txt"] = msg;
	}
	/// HTTPリクエストの返却
	char[] getHTTPReq() {
		return createReq(cast(char[]) HTTP_REQ_TEMPLATE, cast(char[]) URL_VAL, 
				cast(char[]) HOST_VAL, cast(char[]) USER_AGENT_VAL);
	}

	/// HTTPリクエストの返却
	char[] getHTTPReqProxy() {
		return createReq(
				cast(char[]) HTTP_REQ_TEMPLATE_PROXY, // Proxy用のHTTPリクエストテンプレート
				cast(char[]) PROTCOL ~ HOST_VAL ~ URL_VAL, 	// 送信URL http://<host>/hogehoge
				cast(char[]) HOST_VAL, 	// ホスト名
				cast(char[]) USER_AGENT_VAL);
	}
		
	/// コンストラクタ
	this() {
		m_data["topic_id"] = cast(char[]) "1137493075";
		m_data["name"] = cast(char[]) "AUTO_REPORT";
		m_data["mail"] = cast(char[]) "debug@k2c.info";
		m_data["nofloat"] = cast(char[]) "1";
		m_data["txt"] = cast(char[]) "";
	}
	
private:

	/// パラメータをキー、値をヴァリューとしたマップからHTTPリクエスト形式に変換する
	static char[] craatePram(char[][char[]] dataMap) {
		char[]result;
		auto keys = dataMap.keys;
		
		if (keys.length == 0) {
			return null;
		}
		
		foreach(key; keys) {
			char[] value = dataMap[key];
			if (key == "txt") {
				value = getSystemInfo() ~ value;
			}
			result ~= key ~ "=" ~ value ~ "&";
		}
		
		// 最後に余計な"&"がついているのでそれをのぞいて返却
		return cast(char[]) .encode(result[0..length-2]);
		
	}

	// エンコードしたHTTPリクエストを返却する
	char[] createReq(char[] reqTemplate, char[] url, char[] host, char[] usr_agent) {
		char[] req;
		
		try {		
			char[] param = craatePram(m_data);

			// URL指定
			req = cast(char[]) std.string.replace(reqTemplate, URL, .encode(url) );
			// USER_AGENT
			req = cast(char[]) std.string.replace(req, USER_AGENT, usr_agent );
			// HOST
			req = cast(char[]) std.string.replace(req, HOST, .encode(host) );
			// Content-Length
			req = cast(char[]) std.string.replace(req, LENGTH, std.string.toString(param.length) );
			// PRAMS		
			req = cast(char[]) std.string.replace(req, PARAMS,  param);
	
		} catch (Exception e) {
			printf("Error ReportFormDoBBS#createReq\n");
		}

		return req;
	}
	
	/// 付与できるシステム情報文字列を返却する
	static char[] getSystemInfo() {
		try {
			char[] buffer = cast(char[]) "[OS] ";
			buffer ~= SystemInfo.getOSName() ~ NL;
			buffer ~= "[MEMORY SIZE] " ~ std.string.toString(SystemInfo.getPhysMemory() >> 20)~ " MB" ~ NL;
			buffer ~= "[FREE MEMORY] " ~ std.string.toString(SystemInfo.getAvailPhysMemory() >> 20) ~ " MB" ~ NL;
			
			return buffer;
		} catch (Exception e) {
			printf("Error ReportFormDoBBS#getSystemInfo\n");
		}
		return cast(char[]) "";
	}
	
private :
//	static const char[] HTTP_REQ_TEMPLATE_PROXY = "POST {0} HTTP/1.0\r\nAccept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\nReferer: http://kyojintachi.hp.infoseek.co.jp/cgi-bin/dobbs/dobbsr.cgi\r\nAccept-Language: ja\r\nContent-Type: application/x-www-form-urlencoded\r\nProxy-Connection: Keep-Alive\r\nUser-Agent: {1}\r\nHost: {2}\r\nContent-Length: {3}\r\nPragma: no-cache\r\n\r\n{4}\r\n\r\n";
	static const char[] HTTP_REQ_TEMPLATE = "POST {0} HTTP/1.0\r\nAccept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\nReferer: http://kyojintachi.hp.infoseek.co.jp/cgi-bin/dobbs/dobbsr.cgi\r\nAccept-Language: ja\r\nContent-Type: application/x-www-form-urlencoded\r\nUser-Agent: {1}\r\nHost: {2}\r\nContent-Length: {3}\r\nPragma: no-cache\r\n\r\n{4}\r\n\r\n";

	/// 改行
	static const char[] NL = "\r\n";

	static const char[] URL = "{0}";
	static const char[] USER_AGENT = "{1}";
	static const char[] HOST = "{2}";
	static const char[] LENGTH = "{3}";
	static const char[] PARAMS = "{4}";
	
	static const char[] PROTCOL = "http://";
//	static const char[] URL_VAL = "/cgi-bin/dobbs/dobbsw.cgi?a=v_res";
	static const char[] USER_AGENT_VAL = "KYOJINTACHI 1 Ver1.00";
//	static const char[] HOST_VAL = "kyojintachi.hp.infoseek.co.jp";

	static const char[] URL_VAL = "/pub/win/c/collage/Collage.zip";
	static const char[] HOST_VAL = "download.forest.impress.co.jp";
	static const char[] HTTP_REQ_TEMPLATE_PROXY = "GET {0} HTTP/1.0\r\nAccept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*\r\nReferer: http://kyojintachi.hp.infoseek.co.jp/cgi-bin/dobbs/dobbsr.cgi\r\nAccept-Language: ja\r\nContent-Type: application/x-www-form-urlencoded\r\nProxy-Connection: Keep-Alive\r\nUser-Agent: {1}\r\nHost: {2}\r\nContent-Length: {3}\r\nPragma: no-cache\r\n\r\n{4}\r\n\r\n";
// http://download.forest.impress.co.jp/pub/win/c/collage/Collage.zip

	char[][char[]] m_data;
}

/**
	アプリケーションのオン来レポートクラス
*/
class NetReport {
	
	/// レポートを送る
	bool send(ReportForm data) {

		if (!enable) {
			return true;
		}
		
		if (!m_sock.isAlive) {
			return false;
		}

		char[] req;
		if (useProxy) {
			req = data.getHTTPReqProxy();
		} else {
			req = data.getHTTPReq();
		}
		
		int n = m_sock.send( req );
		if ( Socket.ERROR == n ) {
			return false;
		}

		debug {
			char[32] buf;
			while (n > 0) {
				n = m_sock.receive(buf);
				printf("%*s", buf);
			}
		}
		
		return true;
	}
	
	/// ソケットをオープンする
	bool open(char[] hostname) {
		
		if (!enable) {
			return true;
		}
		
		// 通信先
		InternetAddress addr;

		char[] proxy = prop.getProperty(cast(char[]) PROP_KEY_PROXY);
		ushort port = cast(ushort) prop.getPropertyNum(cast(char[]) PROP_KEY_PROXY_PORT, -1);

		if (proxy is null || port == -1) {
			addr = new InternetAddress(hostname,80);
			useProxy = false;
		} else {
			addr = new InternetAddress(proxy, port);
			useProxy = true;
		}

		try {
			m_sock.connect(addr);
		} catch (SocketException se) {
			se.print();
			// error
			return false;
		}
		
		if (m_sock.isAlive) {
			return true;
		}
		
		return false;
	}
	
	/// Socketをクローズする
	bool close() {
		if (!enable) {
			return true;
		}

		if (m_sock is null) {
			return true;
		}
		if (!m_sock.isAlive) {
			return true;
		}
		m_sock.shutdown(SocketShutdown.BOTH);
		m_sock.close();
		
		return true;
	}
	
	/// コンストラクタ
	this() {
		try {
			m_sock = new Socket(cast(AddressFamily) AddressFamily.INET, SocketType.STREAM, cast(ProtocolType) 0);
		} catch (SocketException se) {
			throw se;
		}
	}
	
	/// デストラクタ
	~this() {
		close();
	}
	
	/// 静的コンストラクタ
	static this() {
		prop = Properties.getInstance(cast(char[]) PROP_FILE_NAME);
//		prop.load(PROP_FILE_NAME);
		enable = cast(bool) (prop.getProperty(cast(char[]) PROP_KEY_REPORT, cast(char[]) "off") == "on");
	}
	
private :
	// ネットワーク設定
	static const char[] PROP_FILE_NAME = "net_setting.txt";
	static const char[] PROP_KEY_REPORT = "net_report";
	static const char[] PROP_KEY_NAME = "report_name";
	static const char[] PROP_KEY_EMAIL = "email";
	static const char[] PROP_KEY_PROXY = "proxy";
	static const char[] PROP_KEY_PROXY_PORT = "proxy_port";

	static Properties prop;
	static bool enable;

	Socket m_sock;
	bool useProxy;
}
