void ipc_thread_function()
{
	while (true)
	{
		ipc.update();
		Sleep(100);
	}
}
void Reprojector::load(IPC& ipc, bool flipped)
{
	bool serial_first_non_zero = false;
	string serial = "";

	for (int i = 4; i < 10; ++i)
	{
		string str_temp = "";
		str_temp += serial_number[i];

		if (!serial_first_non_zero && str_temp != "0")
			serial_first_non_zero = true;

		if (serial_first_non_zero)
			serial += serial_number[i];
	}

	bool has_complete_calib_data = false;

	if (directory_exists(data_path_current_module))
		if (file_exists(data_path_current_module + "\\0.jpg"))
			if (file_exists(data_path_current_module + "\\1.jpg"))
				if (file_exists(data_path_current_module + "\\stereoCalibData.txt"))
					if (file_exists(data_path_current_module + "\\rect0.txt"))
						if (file_exists(data_path_current_module + "\\rect1.txt"))
							has_complete_calib_data = true;

	if (!has_complete_calib_data)
	{
		static bool block_thread = true;
		ipc.send_message("menu_plus", "show window", "");
		ipc.get_response("menu_plus", "show download", "", [](const string message_body)
		{
			COUT << "unblock" << endl;
			block_thread = false;
		});
		
		while (block_thread)
		{
			ipc.update();
			Sleep(100);
		}

        create_directory(data_path);
        create_directory(data_path_current_module);

		copy_file(executable_path + "\\rectifier.exe", data_path_current_module + "\\rectifier.exe");
		copy_file(executable_path + "\\opencv_core249.dll", data_path_current_module + "\\opencv_core249.dll");
		copy_file(executable_path + "\\opencv_highgui249.dll", data_path_current_module + "\\opencv_highgui249.dll");
		copy_file(executable_path + "\\opencv_imgproc249.dll", data_path_current_module + "\\opencv_imgproc249.dll");
		copy_file(executable_path + "\\opencv_calib3d249.dll", data_path_current_module + "\\opencv_calib3d249.dll");
		copy_file(executable_path + "\\opencv_flann249.dll", data_path_current_module + "\\opencv_flann249.dll");
		copy_file(executable_path + "\\opencv_features2d249.dll", data_path_current_module + "\\opencv_features2d249.dll");

		//http://s3-us-west-2.amazonaws.com/ractiv.com/data/
		//http://d2i9bzz66ghms6.cloudfront.net/data/

		string param0 = "http://s3-us-west-2.amazonaws.com/ractiv.com/data/" + serial + "/0.jpg";
		string param1 = data_path_current_module + "\\0.jpg";

		string* serial_ptr = &serial;
		IPC* ipc_ptr = &ipc;
		ipc.get_response("menu_plus", "download", param0 + "`" + param1, [serial_ptr, ipc_ptr](const string message_body)
		{
			if (message_body == "false")
				ipc_ptr->send_message("daemon_plus", "exit", "");
			else
			{
				string param0 = "http://s3-us-west-2.amazonaws.com/ractiv.com/data/" + *serial_ptr + "/1.jpg";
				string param1 = data_path_current_module + "\\1.jpg";

				ipc_ptr->get_response("menu_plus", "download", param0 + "`" + param1, [serial_ptr, ipc_ptr](const string message_body)
				{
					if (message_body == "false")
						ipc_ptr->send_message("daemon_plus", "exit", "");
					else
					{
						string param0 = "http://s3-us-west-2.amazonaws.com/ractiv.com/data/" + *serial_ptr + "/stereoCalibData.txt";
						string param1 = data_path_current_module + "\\stereoCalibData.txt";

						ipc_ptr->get_response("menu_plus", "download", param0 + "`" + param1, [serial_ptr, ipc_ptr](const string message_body)
						{
							if (message_body == "false")
								ipc_ptr->send_message("daemon_plus", "exit", "");
							else
							{
								bool has_complete_calib_data = false;
								while (!has_complete_calib_data)
								{
									system(("cd " + cmd_quote + data_path_current_module + cmd_quote + " && rectifier.exe").c_str());

									if (directory_exists(data_path_current_module))
										if (file_exists(data_path_current_module + "\\0.jpg"))
											if (file_exists(data_path_current_module + "\\1.jpg"))
												if (file_exists(data_path_current_module + "\\stereoCalibData.txt"))
													if (file_exists(data_path_current_module + "\\rect0.txt"))
														if (file_exists(data_path_current_module + "\\rect1.txt"))
															has_complete_calib_data = true;
								}

								block_thread = false;
							}
						});
					}
				});
			}
		});

		block_thread = true;

		while (block_thread)
		{
			ipc.update();
			Sleep(100);
		}
	}

	ifstream file_stereo_calib_data(data_path_current_module + "\\stereoCalibData.txt");

	bool is_number_new = false;
	bool is_number_old = false;

	int block_count = 0;
	int block[4];

	vector<Point> disparity_data;

	string str_num_temp = "";
	string disparities_string = "";
	
	while (getline(file_stereo_calib_data, disparities_string))
	{
		const int i_max = disparities_string.length();
		for (int i = 0; i < i_max; ++i)
		{
			string str_temp = "";
			str_temp += disparities_string[i];

			if (str_temp != "," && str_temp != ";")
				is_number_new = true;
			else
				is_number_new = false;

			if (is_number_new)
			{
				if (!is_number_old)
					str_num_temp = str_temp;
				else
					str_num_temp += str_temp;
			}
			else if (is_number_old)
			{
				block[block_count] = stoi(str_num_temp);
				++block_count;
			}

			if (block_count == 3)
			{
				bool found = false;

				for (int a = 0; a < disparity_data.size(); ++a)
				{
					if (disparity_data[a].x == block[0])
					{
						found = true;
						disparity_data[a].y = (disparity_data[a].y + abs(block[1] - block[2])) / 2;
					}
					else if (disparity_data[a].y == abs(block[1] - block[2]))
					{
						found = true;
						disparity_data[a].x = min(disparity_data[a].x, block[0]);
					}
				}
				if (!found)
					disparity_data.push_back(Point(block[0], abs(block[1] - block[2])));

				block_count = 0;
			}

			is_number_old = is_number_new;
		}
	}
	sort(disparity_data.begin(), disparity_data.end(), compare_point_x());

	double *t, *y;

	t = new double[disparity_data.size()];
	y = new double[disparity_data.size()];

	for (unsigned int a = 0; a < disparity_data.size(); a++)
	{
		t[a] = (double)(disparity_data[a].y);
		y[a] = (double)(disparity_data[a].x);
	}
	CCurveFitting cf;
	cf.curve_fitting4(t, disparity_data.size(), y, &a_out, &b_out, &c_out, &d_out);

	delete []t;
	delete []y;

	ifstream file0(data_path_current_module + "\\rect0.txt");
	is_number_new = false;
	is_number_old = false;
	block_count = 0;

	rect_mat0 = new Point*[WIDTH_LARGE];
	for (int i = 0; i < WIDTH_LARGE; ++i)
		rect_mat0[i] = new Point[HEIGHT_LARGE];

	string rect0_string = "";
	while (getline(file0, rect0_string))
	{
		const int i_max = rect0_string.length();
		for (int i = 0; i < i_max; ++i)
		{
			string str_temp = "";
			str_temp += rect0_string[i];

			if (str_temp != " " && str_temp != "," && str_temp != ";")
				is_number_new = true;
			else
				is_number_new = false;

			if (is_number_new)
			{
				if (!is_number_old)
					str_num_temp = str_temp;
				else
					str_num_temp += str_temp;
			}
			else if (is_number_old)
			{
				block[block_count] = stoi(str_num_temp);
				++block_count;
			}
			if (block_count == 4)
			{
				if (!flipped)
					rect_mat0[block[0]][block[1]] = Point(block[2], block[3]);
				else
					rect_mat0[block[0]][HEIGHT_LARGE_MINUS - block[1]] = Point(block[2], block[3]);

				block_count = 0;
			}
			is_number_old = is_number_new;
		}
	}
	ifstream file1(data_path_current_module + "\\rect1.txt");
	is_number_new = false;
	is_number_old = false;
	block_count = 0;

	rect_mat1 = new Point*[WIDTH_LARGE];
	for (int i = 0; i < WIDTH_LARGE; ++i)
		rect_mat1[i] = new Point[HEIGHT_LARGE];

	string rect1_string = "";
	while (getline(file1, rect1_string))
	{
		const int i_max = rect1_string.length();
		for (int i = 0; i < i_max; ++i)
		{
			string str_temp = "";
			str_temp += rect1_string[i];

			if (str_temp != " " && str_temp != "," && str_temp != ";")
				is_number_new = true;
			else
				is_number_new = false;

			if (is_number_new)
			{
				if (!is_number_old)
					str_num_temp = str_temp;
				else
					str_num_temp += str_temp;
			}
			else if (is_number_old)
			{
				block[block_count] = stoi(str_num_temp);
				++block_count;
			}
			if (block_count == 4)
			{
				if (!flipped)
					rect_mat1[block[0]][block[1]] = Point(block[2], block[3]);
				else
					rect_mat1[block[0]][HEIGHT_LARGE_MINUS - block[1]] = Point(block[2], block[3]);

				block_count = 0;
			}
			is_number_old = is_number_new;
		}
	}
}