#include <iostream>
#include <vector>
#include <string>
#include <time.h>
#include <stdlib.h>
///包含这个工具文件以使用分组排列组合算法
#include "nmcalc.h"
using namespace NM_CALC;	//使用命名空间
using namespace std;

void prepare_task(nmserial<string> * task);
void serial_deal(nmserial<string> * task);
//演示
int main()
{
	srand(time(0));
	///测试10次
	for (int test = 0; test < 10; ++ test)
	{
		printf ("Test %d:\n",test);
		/// 0. 一次联合排列组合由一个状态机完成，状态机可以批量的返回结果，速度非常快。
		nmserial<string> state_machine;
		/// 设置状态机每次返回的规模
		state_machine.set_batch_deal(1024*1024);	//每次返回1M个排列组合
		state_machine.set_group_deal(65536);		//每组内，以该参数为单位记忆缓存提高速度

		/// 1. 随机产生排列需求，实际过程中应使用真实数据填写，
		/// 元素类型也不一定是string。这里使用string是为了打印美观。
		prepare_task(&state_machine);

		/// 2. 开始处理，不断获取批量数据
		serial_deal(&state_machine);

		printf ("\n");
	}
	printf ("\n Finished.");

	return 0;
}

void serial_deal(nmserial<string> * state)
{
	///1.准备一个矩阵用来存放结果窗口
	std::vector<std::vector<string> > vec_results;
	///2.调用开始方法，产生首组结果，返回总共的规模。
	unsigned long long totalAmounts = state->serial_nm_begin(vec_results);

	printf (" = %lld\n" ,totalAmounts);

	///3.不断获取一组排列组合并处理
	int currGpsz = vec_results.size();
	unsigned long long currDeal = 0;
	//最终结果
	while (currGpsz)
	{
		//此处可以并行化
		/*
#pragma omp parallel for
		for (int gi = 0;gi<currGpsz;++gi)
		{
			const vector<string> &vec_result = vec_results[gi];
			//开始干活,这里只是打印出顺序
		}
		*/
		currDeal += currGpsz;
		//打印本组完成时的进度
		for (int j = 0; j < state->total_out(); ++j)
			printf("%s ",vec_results[currGpsz-1][j].c_str());
		printf (",%6.2lf%%\n",double(100.0*currDeal / totalAmounts));

		///3.1 获取下一组数据。注意，vec_results 已经分配好内存，不会重复分配
		currGpsz = state->serial_nm_next(vec_results);
		fflush(stdout);
	}//end while (currGpsz)


}


void prepare_task(nmserial<string> * state)
{
	//分 serial_count 组
	const int serial_count = rand()%2+3;
	printf ("serial_count = %d\n",serial_count);
	//插入若干字符，准备数据
	for (int i=0;i<serial_count;++i)
	{
		state->vec_groups.push_back(vector<string>());
		//为本组追加插入随机个数
		int n = rand() % 3 + 3;
		int m = n - rand()%2 - 1;
		if (i==serial_count-1)
		{
			m = 6;
			n = 10;
		}
		//通过向量 state.group_m 指定各组的 m
		state->group_m.push_back(m);
		//插入各组元素
		for (int j = 0; j < n; j++)
		{
			string name;
			name.push_back('A' + i);
			int ch = j;
			string tail;
			do
			{
				string dec;
				dec.push_back('0'+ ch % 10);
				tail = dec + tail;
				ch /= 10;
			}while (ch);
			name += tail;
			state->vec_groups[i].push_back(name);
		}
		//随机决定本组是 PNM 还是 CNM
		if (rand()%2)
		{
			//通过向量 state.group_type 指定各组的策略是PNM还是CNM
			state->group_type.push_back(nmserial<string>::func_CNM);
			printf ("C(%d,%d) ",n,m);
		}
		else
		{
			//通过向量 state.group_type 指定各组的策略是PNM还是CNM
			state->group_type.push_back(nmserial<string>::func_PNM);
			printf ("P(%d,%d) ",n,m);
		}
	}
}
