#include "StdAfx.h"
#include <apl_api.h>
#include "aplWorkFlowManager.h"

#include "dictionary.h"
#include "ProcessDlg.h"
#include "TaskDlg.h"
#include "CommonETDialog.h"
#include "TmplDialog.h"
#include "SignDlg.h"
#include "TaskTimesDialog.h"
#include "ListDialog.h"
#include "StPntSelectDlg.h"

#include "SelProcTemplDlg.h"
#include "MProcStartDialog.h"

#include "ViewWfTemplateDlg.h"
#include "SelectProcessTemplDlg.h"
#include "SelConnectorDlg.h"

#include "CWfColorDialog.h"

//*******************************************************************************
BOOL aplTestCyrcleInProcess(CaplWorkFlowManager* wf_mgr, 
						 CaplInstance* task, CaplInstance* sub_process)
{
	if(!wf_mgr) return -1;
	if(!wf_mgr->m_data || !wf_mgr->m_data->IsConnected()) return -1;
	if(!task) return -1;
	if(!sub_process) return -1;

	CaplLoadData ld(wf_mgr->m_data,DEF_SOURCE);

	aplExtent ext;
	wf_mgr->GetProcessTasks(sub_process, ext);
	for(int i= 0; i<ext.GetSize(); i++)
	{
		ld.ClearQuery();
		int n= ld.AddQuery(-1,ext[i]);
		ld.AddQuery(_T('d'), n, 0, wf_mgr->a_task_sub_proc, true);
		ld.AddQuery(_T('d'), n, 0, wf_mgr->a_task_state, true);
		ld.LoadEx();
		
		CString buf;
		wf_mgr->m_data->GetAttr(ext[i], wf_mgr->a_task_state, buf);
		if(buf!=_T("work")) continue;

		if(ext[i]==task)
		{
			if(wf_mgr->m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Ошибка при задании подпроцесса.\n\nЦикл в процессе."), MB_OK|MB_ICONERROR);
			return 0;
		}
		else
		{

			CaplAggr sub_procs;
			CaplInstance* inst= NULL;
			wf_mgr->m_data->GetAttr(ext[i], wf_mgr->a_task_sub_proc, sub_procs);
			for(int j= 0; j<sub_procs.GetSize(); j++)
			{
				sub_procs.GetByIndex(j, inst);
				if(inst && 0==aplTestCyrcleInProcess(wf_mgr, task, inst))
				{
					return 0;
				}
			}
		}
	}

	return 1;
}
//*******************************************************************************
void aplSortWfInstances(CaplWorkFlowManager* wf_mgr, aplExtent& instances, int iLeft, int iRight)
{
	if(!wf_mgr) return;
	if(!wf_mgr->m_data || !wf_mgr->m_data->IsConnected()) return;
	if(iLeft==iRight) return;

	CaplInstance* testInst= instances.GetAt((iLeft+iRight) / 2);	
	if(!testInst) return;
	
	CString sTestDate;
	wf_mgr->m_data->GetAttr(testInst, wf_mgr->a_act_inst_start_date, sTestDate);
		
	int i= iLeft;
	int j= iRight;
	CString sMinDate, sMaxDate;		
	CaplInstance* swap= NULL;

	do
	{		
		while(1)
		{
			wf_mgr->m_data->GetAttr(instances[i], wf_mgr->a_act_inst_start_date, 
				sMinDate);
			if(sMinDate<sTestDate)if(!sMinDate.IsEmpty()){i++; continue;}
			break;
		}
		while(1)
		{
			wf_mgr->m_data->GetAttr(instances[j], wf_mgr->a_act_inst_start_date, 
				sMaxDate);
			if(sMaxDate>sTestDate){j--; continue;}
			break;
		}
		
		if(i<=j)
		{
			swap= instances[i];
			instances.SetAt(i, instances[j]);
			instances.SetAt(j, swap);
			i++;
			j--;
		}

	}while(i<=j);

	if(iLeft<j) aplSortWfInstances(wf_mgr, instances, iLeft, j);
	if(i<iRight) aplSortWfInstances(wf_mgr, instances, i, iRight);
}


BOOL aplIsPersonOrgElement(CaplAPI* api, CaplInstance* Element, CaplInstance* person/* =NULL */)
{
	if(!api) return FALSE;
	if(!api->m_data.IsConnected()) return FALSE;
	if(!Element) return FALSE;
	
	CaplInstance* inst;
	if(!person)person= api->m_appr_mgr.GetCurrentPerson();
	else
	{
		if (api->m_data.IsKindOf(person, api->m_appr_mgr.e_official))
			api->m_data.GetAttr(person, api->m_appr_mgr.a_official_act_person, person);
	}
	if(!person) return FALSE;

	if(api->m_data.IsKindOf(Element, api->m_appr_mgr.e_pers_org))
	{
		api->m_data.GetAttr(Element, api->m_appr_mgr.a_po_the_pers, Element);
		if(Element==person)
		{
			return TRUE;
		}
	}
	else if(api->m_data.IsKindOf(Element, api->m_appr_mgr.e_person))
	{
		if(Element==person)
		{
			return TRUE;
		}
	}
	else if(api->m_data.IsKindOf(Element,  api->m_appr_mgr.e_org))
	{
		/*  
		ЯАИ:  
		Переделал GetUserProcessTempList  ибо тормозила
		Тут просто унифицировал механизм.

		aplExtent curPersWG, org_rel, per_org;
		api->m_data.GetEntityExtent(api->m_appr_mgr.e_org_rel, org_rel);
		api->m_data.GetEntityExtent(api->m_appr_mgr.e_pers_org, per_org);
		
		if(-1!=curPersWG.Find(Element) || aplIsPersonsWorkGroup(api, 
			Element, person, org_rel, per_org, curPersWG))
		{
			return TRUE;
		}
		*/
		aplExtent ext_owner_wg;
		api->m_appr_mgr.GetAllActualPersOrgs(person,ext_owner_wg);
		if(aplQFindInstInExtent(ext_owner_wg,Element,false)>=0) return TRUE;
	}
	else if(api->m_data.IsKindOf(Element, api->m_appr_mgr.e_official))
	{
		api->m_data.GetAttr(Element, api->m_appr_mgr.a_official_act_person, inst);
		if(inst==person)
		{
			return TRUE;
		}
	}

	return FALSE;
}

BOOL CaplWorkFlowManager::m_b_mark_work_with_color=TRUE;  // выделять работы цветом
BOOL CaplWorkFlowManager::m_b_mark_ended_work_with_color=TRUE; // выделятьзавершенные работы цветом
BOOL CaplWorkFlowManager::m_b_not_show_task_of_future_process=FALSE;
int  CaplWorkFlowManager::m_i_mark_work_with_color_warning_time=3;  // За сколько дней до завершения выделять ораньжевым

bool CaplWorkFlowManager::LoadOptions()
{
	CWinApp *app=AfxGetApp();
	if(0==app) return false;
	m_b_mark_work_with_color=app->GetProfileInt(_T("Workflow"),_T("m_b_mark_work_with_color"),1);
	m_b_mark_ended_work_with_color=app->GetProfileInt(_T("Workflow"),_T("m_b_mark_ended_work_with_color"),1);
	m_b_not_show_task_of_future_process=app->GetProfileInt(_T("Workflow"),_T("m_b_not_show_task_of_future_process"),0);
	m_i_mark_work_with_color_warning_time=app->GetProfileInt(_T("Workflow"),_T("m_i_mark_work_with_color_warning_time"),3);
	return true;
}
bool CaplWorkFlowManager::SaveOptions()
{
	CWinApp *app=AfxGetApp();
	if(0==app) return false;
	app->WriteProfileInt(_T("Workflow"),_T("m_b_mark_work_with_color"),m_b_mark_work_with_color);
	app->WriteProfileInt(_T("Workflow"),_T("m_b_mark_ended_work_with_color"),m_b_mark_ended_work_with_color);
	app->WriteProfileInt(_T("Workflow"),_T("m_b_not_show_task_of_future_process"),m_b_not_show_task_of_future_process);
	app->WriteProfileInt(_T("Workflow"),_T("m_i_mark_work_with_color_warning_time"),m_i_mark_work_with_color_warning_time);
	return true;
}

bool CheckPersonNotify(CaplAPI *m_api, CaplInstance *person, LPCTSTR option)
{
	if(0==m_api) return false;
	if(0==person) return false;
	if(0==option) return false;
	if(_T('\0')==option[0]) return false;

	if(m_api->m_data.IsKindOf(person,m_api->m_appr_mgr.e_official))
		m_api->m_data.GetAttr(person, m_api->m_appr_mgr.a_official_act_person, person);
	if(0==person) return false;

	if(person==m_api->m_appr_mgr.GetCurrentPerson())  return false;

	if(_T('#')==option[0])
	{
		CString sOpt=option;
		if(sOpt==_T("#CompleteProcessNotify")) option=APL_NO_T("Настройка Workflow\\Уведомлять владельца о завершении процесса");
		else if(sOpt==_T("#CancelTaskNotifyOwner")) option=APL_NO_T("Настройка Workflow\\Уведомлять владельца об отмене задания");
		else if(sOpt==_T("#CancelTaskNotifyExecutor")) option=APL_NO_T("Настройка Workflow\\Уведомлять исполнителя об отмене задания");
		else if(sOpt==_T("#SuspendTaskNotifyOwner")) option=APL_NO_T("Настройка Workflow\\Уведомлять владельца об остановке задания");
		else if(sOpt==_T("#SuspendTaskNotifyExecutor")) option=APL_NO_T("Настройка Workflow\\Уведомлять исполнителя об остановке задания");
		else if(sOpt==_T("#CompleteTaskNotifyOwner")) option=APL_NO_T("Настройка Workflow\\Уведомлять владельца о завершении задания");
		else if(sOpt==_T("#CompleteTaskNotifyExecutor")) option=APL_NO_T("Настройка Workflow\\Уведомлять исполнителя о завершении задания");
		//else if(sOpt==_T("#NewTaskNotify")) option=APL_NO_T("Настройка Workflow\\Уведомлять исполнителя о выдаче задания");
		// ЯАИ: 2024.08.14 В настройках задается параметр "уведомлять о запуске", но нет "уведомлять о выдаче"
		// Дабы не ломать настройку сделано одинаково
		else if(sOpt==_T("#NewTaskNotify")) option=APL_NO_T("Настройка Workflow\\Уведомлять исполнителя о запуске задания");
		else if(sOpt==_T("#RunTaskNotify")) option=APL_NO_T("Настройка Workflow\\Уведомлять исполнителя о запуске задания");
		else
		{
			CString buf; buf.Format(APL_T("Ошибка отправки уведомления (%s)!"),option);
			AfxMessageBox(buf,MB_ICONSTOP|MB_OK);
			return false;
		}
	}

	int iVal=m_api->m_options_mgr.GetIntPersonOption(person, option);

	if(1==iVal) return true;
	if(-1==iVal) return false;

	m_api->m_options_mgr.GetOptionValueBN(option, iVal, 0);
	if(iVal!=0) return true;
	return false;
}

//*******************************************************************************
void CaplWorkFlowManager::LoadParamsFromDB()
{
	if(0==m_api) return;
}

//*******************************************************************************
bool CaplWorkFlowManager::Attach(CaplAPI *api)
{
	if(api==0) {Detach();return false;}
	CaplStepManager::Attach(api);
	
	e_action= m_data->GetEntityBN(S::apl_action);
	a_action_id= m_data->GetAttrDefinition(e_action, S::id);
	a_action_name= m_data->GetAttrDefinition(e_action, S::name);
	a_action_dscr= m_data->GetAttrDefinition(e_action, S::description);
	
	e_proc_tmpl= m_data->GetEntityBN(S::apl_process_template);
	a_proc_tmpl_holders= m_data->GetAttrDefinition(e_proc_tmpl, S::holders);
	a_proc_tmpl_managers= m_data->GetAttrDefinition(e_proc_tmpl, _T("managers"));
	a_proc_tmpl_duration= m_data->GetAttrDefinition(e_proc_tmpl, S::duration);
	a_proc_tmpl_var= m_data->GetAttrDefinition(e_proc_tmpl, S::variables);
	a_proc_tmpl_state= m_data->GetAttrDefinition(e_proc_tmpl, S::state);
	a_proc_tmpl_cols= m_data->GetAttrDefinition(e_proc_tmpl, _T("page_cols"));
	a_proc_tmpl_hight= m_data->GetAttrDefinition(e_proc_tmpl, _T("page_hight"));
	a_proc_tmpl_width= m_data->GetAttrDefinition(e_proc_tmpl, _T("page_width"));
	a_proc_tmpl_rows= m_data->GetAttrDefinition(e_proc_tmpl, _T("page_rows"));
	a_proc_tmpl_ortogonal= m_data->GetAttrDefinition(e_proc_tmpl, _T("ortogonal"));
	a_proc_tmpl_editor= m_data->GetAttrDefinition(e_proc_tmpl, _T("editor"));
	a_proc_tmpl_author_txt= m_data->GetAttrDefinition(e_proc_tmpl, _T("author_txt"));
	a_proc_tmpl_is_system= m_data->GetAttrDefinition(e_proc_tmpl, _T("is_system"));
	a_proc_tmpl_add_wo_function= m_data->GetAttrDefinition(e_proc_tmpl, _T("add_wo_function"));
	a_proc_tmpl_add_wo_module= m_data->GetAttrDefinition(e_proc_tmpl, _T("add_wo_module"));
	a_proc_tmpl_set_enddate_by_task= m_data->GetAttrDefinition(e_proc_tmpl, _T("set_enddate_by_task"));
	a_proc_tmpl_allow_owner_end_any_task= m_data->GetAttrDefinition(e_proc_tmpl, _T("allow_owner_end_any_task"));

	e_act_tmpl= m_data->GetEntityBN(S::apl_activity_template);
	a_act_tmpl_proc_tmpl= m_data->GetAttrDefinition(e_act_tmpl, S::of_process_template);
	a_act_tmpl_cx= m_data->GetAttrDefinition(e_act_tmpl, _T("cx"));
	a_act_tmpl_cy= m_data->GetAttrDefinition(e_act_tmpl, _T("cy"));
	a_act_tmpl_color= m_data->GetAttrDefinition(e_act_tmpl, _T("color"));
	a_act_tmpl_point= m_data->GetAttrDefinition(e_act_tmpl, _T("point"));
	a_act_tmpl_font= m_data->GetAttrDefinition(e_act_tmpl, _T("font_el"));
	a_act_tmpl_width= m_data->GetAttrDefinition(e_act_tmpl, _T("width"));

	e_activity= m_data->GetEntityBN(S::apl_activity);
	a_activity_duration= m_data->GetAttrDefinition(e_activity, S::duration);
//	a_activity_route= m_data->GetAttrDefinition(e_activity, S::route);
	a_activity_sub_proc_tmpl= m_data->GetAttrDefinition(e_activity, _T("sub_process_templates"));
	a_activity_ass_tmpl= m_data->GetAttrDefinition(e_activity, S::associated_template);
	a_activity_executors= m_data->GetAttrDefinition(e_activity, S::executors);
	a_activity_managers= m_data->GetAttrDefinition(e_activity, _T("managers"));
	a_activity_st_mode= m_data->GetAttrDefinition(e_activity, S::start_mode);
	a_activity_st_cond= m_data->GetAttrDefinition(e_activity, S::start_condition);
	a_activity_fn_mode= m_data->GetAttrDefinition(e_activity, S::finish_mode);
	a_activity_fn_cond= m_data->GetAttrDefinition(e_activity, S::finish_condition);
	a_activity_role= m_data->GetAttrDefinition(e_activity, S::role);
	a_activity_ed_st_mod= m_data->GetAttrDefinition(e_activity, _T("editor_module"));
	a_activity_ed_st_fun= m_data->GetAttrDefinition(e_activity, _T("editor_function"));
	a_activity_ed_st_par= m_data->GetAttrDefinition(e_activity, _T("editor_param"));
	a_activity_ed_fn_mod= m_data->GetAttrDefinition(e_activity, _T("finish_editor_module"));
	a_activity_ed_fn_fun= m_data->GetAttrDefinition(e_activity, _T("finish_editor_function"));
	a_activity_ed_fn_par= m_data->GetAttrDefinition(e_activity, _T("finish_editor_param"));
	a_activity_waiting_time= m_data->GetAttrDefinition(e_activity, _T("waiting_time"));
	a_activity_not_sign= m_data->GetAttrDefinition(e_activity, _T("not_sign"));
	a_activity_add_wo= m_data->GetAttrDefinition(e_activity, _T("add_wo"));
	a_activity_give_the_process_owner= m_data->GetAttrDefinition(e_activity, _T("give_the_process_owner"));
	CHECK_ZERO_ATTR(a_activity_stop_another_task, m_data->GetAttrDefinition(e_activity, _T("stop_another_task")));
	
	e_act_inst= m_data->GetEntityBN(S::apl_action_instance);
	a_act_inst_start_date= m_data->GetAttrDefinition(e_act_inst, S::start_date);
	a_act_inst_finish_date= m_data->GetAttrDefinition(e_act_inst, S::finish_date);
	a_act_inst_check_date= m_data->GetAttrDefinition(e_act_inst, S::check_date);
	a_act_inst_end_date= m_data->GetAttrDefinition(e_act_inst, S::end_date);
	a_act_inst_prior= m_data->GetAttrDefinition(e_act_inst, S::priority);
	a_act_inst_percent= m_data->GetAttrDefinition(e_act_inst, S::percentage);
	a_act_inst_susp_time= m_data->GetAttrDefinition(e_act_inst, _T("suspend_time"));
	a_act_inst_last_susp_date= m_data->GetAttrDefinition(e_act_inst, _T("suspend_date"));
	
	e_proc= m_data->GetEntityBN(S::apl_process);
	a_proc_of_tmpl= m_data->GetAttrDefinition(e_proc, S::of_process_template);
	a_proc_task_prot= m_data->GetAttrDefinition(e_proc, S::task_prototypes);
	a_proc_owner= m_data->GetAttrDefinition(e_proc, S::owner);
	a_proc_manager= m_data->GetAttrDefinition(e_proc, _T("manager"));
	a_proc_state= m_data->GetAttrDefinition(e_proc, S::state);
	a_proc_first_activity= m_data->GetAttrDefinition(e_proc, S::first_activity);
	a_proc_wo= m_data->GetAttrDefinition(e_proc, S::work_objects);
	a_proc_archive_date= m_data->GetAttrDefinition(e_proc, _T("archive_date"));
	a_proc_process_prot= m_data->GetAttrDefinition(e_proc, _T("process_prototype"));
	a_proc_not_for_work= m_data->GetAttrDefinition(e_proc, _T("not_for_work_obj"));

	e_proc_prot= m_data->GetEntityBN(_T("apl_process_prototype"));
	a_proc_prot_tmpl= m_data->GetAttrDefinition(e_proc_prot, _T("process_template"));
	a_proc_prot_name= m_data->GetAttrDefinition(e_proc_prot, _T("name"));

	e_task_tmpl= m_data->GetEntityBN(S::apl_task_prototype);
	a_task_tmpl_performer= m_data->GetAttrDefinition(e_task_tmpl, S::default_performer);
	a_task_tmpl_performers= m_data->GetAttrDefinition(e_task_tmpl, _T("posible_performers"));
	a_task_tmpl_manager= m_data->GetAttrDefinition(e_task_tmpl, S::default_manager);
	a_task_tmpl_duration= m_data->GetAttrDefinition(e_task_tmpl, S::default_duration);
	a_task_tmpl_waiting_time= m_data->GetAttrDefinition(e_task_tmpl, _T("default_waiting_time"));
	a_task_tmpl_activity= m_data->GetAttrDefinition(e_task_tmpl, S::of_activity);
	a_task_tmpl_id= m_data->GetAttrDefinition(e_task_tmpl, S::default_id);
	a_task_tmpl_name= m_data->GetAttrDefinition(e_task_tmpl, S::default_name );
	a_task_tmpl_status= m_data->GetAttrDefinition(e_task_tmpl, _T("default_status"));
	a_task_tmpl_role= m_data->GetAttrDefinition(e_task_tmpl, _T("default_role"));
	a_task_tmpl_proc_prot= m_data->GetAttrDefinition(e_task_tmpl, _T("process_prototype"));
		
	e_task= m_data->GetEntityBN(S::apl_task);
	a_task_activity= m_data->GetAttrDefinition(e_task, S::of_activity);
	a_task_proc= m_data->GetAttrDefinition(e_task, S::of_process);
	a_task_performer= m_data->GetAttrDefinition(e_task, S::perfomer);
	a_task_manager= m_data->GetAttrDefinition(e_task, S::manager);
	a_task_state= m_data->GetAttrDefinition(e_task, S::state);
	a_task_sub_proc= m_data->GetAttrDefinition(e_task, S::sub_process);
//	a_task_wo= m_data->GetAttrDefinition(e_task, S::work_objects);
	a_task_prev= m_data->GetAttrDefinition(e_task, S::previous);
	a_task_old_state= m_data->GetAttrDefinition(e_task, _T("state_befor_suspend"));
	a_task_notify_date= m_data->GetAttrDefinition(e_task, _T("notify_date"));
	a_task_reseave_date= m_data->GetAttrDefinition(e_task, _T("reseave_date"));
	CHECK_ZERO_ATTR(a_task_triggered_relations, m_data->GetAttrDefinition(e_task, _T("triggered_relations")));

	e_end_point= m_data->GetEntityBN(S::apl_end_point);
	e_start_point= m_data->GetEntityBN(S::apl_start_point);
	
	e_act_rel= m_data->GetEntityBN(S::apl_action_relationship);
	a_act_rel_id= m_data->GetAttrDefinition(e_act_rel, S::id);
	a_act_rel_name= m_data->GetAttrDefinition(e_act_rel, S::name);
	a_act_rel_dscr= m_data->GetAttrDefinition(e_act_rel, S::description);
	a_act_rel_from= m_data->GetAttrDefinition(e_act_rel, S::from);
	a_act_rel_to= m_data->GetAttrDefinition(e_act_rel, S::to);
	a_act_rel_points= m_data->GetAttrDefinition(e_act_rel, _T("points"));
	a_act_rel_title_point= m_data->GetAttrDefinition(e_act_rel, _T("title_point"));
	a_act_rel_color= m_data->GetAttrDefinition(e_act_rel, _T("color"));
	a_act_rel_font= m_data->GetAttrDefinition(e_act_rel, _T("font_el"));
	a_act_rel_width= m_data->GetAttrDefinition(e_act_rel, _T("width"));
	a_act_rel_arrow_size= m_data->GetAttrDefinition(e_act_rel, _T("arrow_size"));

	e_act_secuence= m_data->GetEntityBN(S::apl_action_secuence);
	a_act_secuence_status= m_data->GetAttrDefinition(e_act_secuence, S::status);
	a_act_secuence_tmpl= m_data->GetAttrDefinition(e_act_secuence, S::of_process_template);
	a_act_secuence_not_sign= m_data->GetAttrDefinition(e_act_secuence, _T("not_sign"));
	CHECK_ZERO_ATTR(a_act_secuence_check_status_4_all_obj, m_data->GetAttrDefinition(e_act_secuence, _T("check_status_4_all_obj")));
	CHECK_ZERO_ATTR(a_act_secuence_check_need_work_4_all_obj, m_data->GetAttrDefinition(e_act_secuence, _T("check_need_work_4_all_obj")));
	
	e_wo= m_data->GetEntityBN(_T("apl_work_object"));
	a_wo_action= m_data->GetAttrDefinition(e_wo, _T("action"));
	a_wo_object= m_data->GetAttrDefinition(e_wo, _T("object"));
	a_wo_for_note= m_data->GetAttrDefinition(e_wo, _T("for_note_only"));

	e_apl_font = m_data->GetEntityBN(_T("apl_font"));
	a_font_name = m_data->GetAttrDefinition(e_apl_font,_T("name"));
	a_font_height = m_data->GetAttrDefinition(e_apl_font,_T("height"));
	a_font_weight = m_data->GetAttrDefinition(e_apl_font,_T("weight"));
	a_font_italic = m_data->GetAttrDefinition(e_apl_font,_T("italic"));
	a_font_char_set = m_data->GetAttrDefinition(e_apl_font,_T("char_set"));


	e_apl_point = m_data->GetEntityBN(_T("apl_point"));
	a_apl_point_x = m_data->GetAttrDefinition(e_apl_point,_T("x"));
	a_apl_point_y = m_data->GetAttrDefinition(e_apl_point,_T("y"));

	m_bUseSignature= true;
	
	m_bCompleteProcessNotify_4_ParentProcess=true; 

	return true;
}
//*******************************************************************************  
void CaplWorkFlowManager::Detach()
{
	e_action= 0;
	a_action_id= 0;
	a_action_name= 0;
	a_action_dscr= 0;
	
	e_proc_tmpl= 0;
	a_proc_tmpl_holders= 0;
	a_proc_tmpl_managers= NULL;
	a_proc_tmpl_duration= 0;
	a_proc_tmpl_var= 0;
	a_proc_tmpl_state= 0;
	a_proc_tmpl_cols= 0;
	a_proc_tmpl_hight= 0;
	a_proc_tmpl_width= 0;
	a_proc_tmpl_rows= 0;
	a_proc_tmpl_add_wo_function= 0;
	a_proc_tmpl_add_wo_module= 0;
	a_proc_tmpl_is_system= 0;
	a_proc_tmpl_set_enddate_by_task=0;
	a_proc_tmpl_allow_owner_end_any_task=0;

	e_act_tmpl= 0;
	a_act_tmpl_proc_tmpl= 0;
	a_act_tmpl_cx= 0;
	a_act_tmpl_cy= 0;
	a_act_tmpl_color= 0;
	a_act_tmpl_point= 0;
	
	e_proc_prot= NULL;
	a_proc_prot_tmpl= NULL;
	a_proc_prot_name= NULL;

	e_activity= 0;
	a_activity_duration= 0;
//	a_activity_route= 0;
	a_activity_sub_proc_tmpl= 0;
	a_activity_ass_tmpl= 0;
	a_activity_executors= 0;
	a_activity_managers= 0;
	a_activity_st_mode= 0;
	a_activity_st_cond= 0;
	a_activity_fn_mode= 0;
	a_activity_fn_cond= 0;
	a_activity_role= 0;
	a_activity_ed_st_mod= 0;
	a_activity_ed_st_fun= 0;
	a_activity_ed_st_par= 0;
	a_activity_ed_fn_mod= 0;
	a_activity_ed_fn_fun= 0;
	a_activity_ed_fn_par= 0;
	a_activity_waiting_time= 0;
	a_activity_not_sign= NULL;
	a_activity_add_wo= 0;	
	a_activity_stop_another_task=0;
	
	e_act_inst= 0;
	a_act_inst_start_date= 0;
	a_act_inst_finish_date= 0;
	a_act_inst_check_date= 0;
	a_act_inst_end_date= 0;
	a_act_inst_prior= 0;
	a_act_inst_percent= 0;
	a_act_inst_susp_time= 0;
	a_act_inst_last_susp_date= 0;

	e_proc= 0;
	a_proc_of_tmpl= 0;
	a_proc_task_prot= 0;
	a_proc_owner= 0;
	a_proc_manager= NULL;
	a_proc_state= 0;
	a_proc_first_activity= 0;
	a_proc_wo= 0;
	a_proc_archive_date= 0;
	a_proc_process_prot= NULL;
	
	e_end_point= NULL;
	e_start_point= NULL;

	e_task_tmpl= 0;
	a_task_tmpl_performer= 0;
	a_task_tmpl_performers= 0;
	a_task_tmpl_manager= 0;
	a_task_tmpl_duration= 0;
	a_task_tmpl_activity= 0;
	a_task_tmpl_id= 0;
	a_task_tmpl_name= 0;
	a_task_tmpl_waiting_time= 0;
	a_task_tmpl_status= NULL;
	a_task_tmpl_role= NULL;
	a_task_tmpl_proc_prot= NULL;
	a_activity_give_the_process_owner=0;
	
	e_task= 0;
	a_task_activity= 0;
	a_task_proc= 0;
	a_task_performer= 0;
	a_task_manager= 0;
	a_task_state= 0;
	a_task_sub_proc= 0;
	a_task_prev= 0;
	a_task_old_state= 0;
	a_task_notify_date= 0;
	a_task_reseave_date= 0;
	a_task_triggered_relations=0;

	e_end_point= 0;
	e_start_point= 0;
	
	e_act_rel= 0;
	a_act_rel_id= 0;
	a_act_rel_name= 0;
	a_act_rel_dscr= 0;
	a_act_rel_from= 0;
	a_act_rel_to= 0;
	a_act_rel_points= 0;
	a_act_rel_title_point= 0;
	a_act_rel_color= 0;
	a_act_rel_font= 0;

	e_act_secuence= 0;
	a_act_secuence_status= 0;
	a_act_secuence_tmpl= 0;
	a_act_secuence_not_sign= NULL;
	a_act_secuence_check_status_4_all_obj=0;
	a_act_secuence_check_need_work_4_all_obj=0;
	
	e_wo= 0;
	a_wo_action= 0;
	a_wo_object= 0;

	e_apl_point=0;
	a_apl_point_x=0;
	a_apl_point_y=0;

}
//*******************************************************************************
bool CaplWorkFlowManager::IsItemLogicalElement(CaplInstance *item)
{
	if(0==item) return false;
	if(item->IsDeleted() ) return false;
	if(item->GetAccessmode()>=aplNO ) return false;

	CaplInstance *activity; 
	if(m_api->m_data.IsKindOf(item,e_task))
	{
		m_api->m_data.GetAttr(item, a_task_activity, activity);
		if(0==activity) return false;
		if(activity->IsDeleted() ) return false;
		if(activity->GetAccessmode()>=aplNO ) return false;
	}
	else activity=item;

	CString buf;
	m_data->GetAttr(activity, a_action_id, buf);
	if(buf==_T("")) return false;
	if(buf[0]==_T('&')) return true;
	return false;
}


//*******************************************************************************
CaplInstance* CaplWorkFlowManager::CreateLogicalTask(CaplInstance* process, CaplInstance* activity, CaplInstance* connector,
		aplExtent &sub_proc, CaplInstance* previous)
{

	if(!m_data || !m_data->IsConnected()) return 0;
	if(process==NULL) return 0;
	if(activity==NULL) return 0;

	// Вызывается раньше 
	//LoadProcessInfo(process);

	if(!IsItemLogicalElement(activity)) return 0;


	CString buf;
	CaplInstance *process_template;
	apidata.GetAttr(process,a_proc_of_tmpl, process_template);


	// Ищекм задачу этого блока ранее созданную
	aplExtent ext;
	CString sSql,s_curdate;
	bool bSqlErr;
	sSql.Format(_T("SELECT_LOAD_ALL Ext_ FROM Ext_{apl_task(.of_process =#%i AND  .of_activity=#%i AND .state='wait' )}END_SELECT"), process->GetId(),activity->GetId());
	
	bSqlErr=m_api->m_data.NET_QueryEditParse(sSql);
	if(bSqlErr) bSqlErr=m_api->m_data.NET_QueryExecute(ext);
	if(!bSqlErr)
	{
		if(m_api->m_ModeInteractive) {	buf=APL_T("Ошибка выполнения запроса в CaplWorkFlowManager::CreateLogicalTask\n\n"); buf+=sSql; 	AfxMessageBox(buf,MB_OK|MB_ICONSTOP);}
		return 0;
	}

	CaplInstance *task_log_el;
	
	if(ext.GetSize()>0) task_log_el=ext[0];
	else
	{
		COleDateTime odt;
		m_api->m_data.NET_GetServerDateTime(odt);
		aplDate2String(odt,s_curdate);

		task_log_el= m_data->CreateInstance(e_task);	
		m_data->PutAttr(task_log_el, a_task_proc, process);
		m_data->PutAttr(task_log_el, a_task_activity, activity);
		m_data->PutAttr(task_log_el, a_act_inst_start_date, s_curdate);
		//m_data->PutAttr(task, a_task_sub_proc, sub_proc);
		m_data->PutAttr(task_log_el, a_task_prev, previous);
		m_data->PutAttr(task_log_el, a_task_state, _T("wait"));

		m_data->GetAttr(activity, a_action_id, buf);
		buf+=_T(" "); buf+=s_curdate;
		m_data->PutAttr(task_log_el, a_action_id, buf);
		
		m_data->GetAttr(activity, a_action_name, buf);
		m_data->PutAttr(task_log_el, a_action_name, buf);

	}

	aplExtent ext_prev_rel_ready;  // предыдущие сработавшие связи
	m_data->GetAttr(task_log_el, a_task_triggered_relations, ext_prev_rel_ready);
	if(0!=connector)ext_prev_rel_ready.Add(connector);
	m_data->PutAttr(task_log_el, a_task_triggered_relations, ext_prev_rel_ready);
	m_api->SaveChanges();


	// Ищем предыдущие связи
	aplExtent ext_prev_rel;
	sSql.Format(_T("SELECT_LOAD_ALL Ext_ FROM Ext_{apl_action_relationship(.to =#%i )}END_SELECT"), activity->GetId());
	bSqlErr=m_api->m_data.NET_QueryEditParse(sSql);
	if(bSqlErr) bSqlErr=m_api->m_data.NET_QueryExecute(ext_prev_rel);
	if(!bSqlErr)
	{
		if(m_api->m_ModeInteractive) {	buf=APL_T("Ошибка выполнения запроса в CaplWorkFlowManager::CreateLogicalTask\n\n"); buf+=sSql; 	AfxMessageBox(buf,MB_OK|MB_ICONSTOP);}
		return 0;
	}

	// Ищкм все ди старые связи сработалиi,
	int i,j;
	bool bFound_i=true;
	for(i=0;i<ext_prev_rel.GetSize();i++)
	{
		CaplInstance *rel=ext_prev_rel[i];
		if(0==rel) continue;

		CaplInstance *prev_action;
		m_data->GetAttr(rel, a_act_rel_from, prev_action);
		if(m_api->m_data.IsKindOf(prev_action,e_start_point)) continue;

		bool bFound_j=false;
		for(j=0;j<ext_prev_rel_ready.GetSize();j++)
		{
			if(rel==ext_prev_rel_ready[j]) {bFound_j=true; break;}
		}
		if(!bFound_j) {bFound_i=false; break;}
	}

	if(!bFound_i) return 0; // Не все предыдущие переходы сработали - выходим
	
	//Сработали все предыдущие переходы  - запускаем след процессы.
	return EndLogicalTask(task_log_el);
}

CaplInstance *CaplWorkFlowManager::EndLogicalTask(CaplInstance *task_log_el)
{
	//Сработали все предыдущие переходы  - запускаем след процессы.
	
	CaplInstance *activity,*process;
	m_data->GetAttr(task_log_el, a_task_proc, process);
	m_data->GetAttr(task_log_el, a_task_activity, activity);

	aplExtent ext_next_rel;
	CString buf, sSql;
	sSql.Format(_T("SELECT_LOAD_ALL Ext_ FROM Ext_{apl_action_relationship(.from =#%i )}END_SELECT"), activity->GetId());
	bool bSqlErr=m_api->m_data.NET_QueryEditParse(sSql);
	if(bSqlErr) bSqlErr=m_api->m_data.NET_QueryExecute(ext_next_rel);
	if(!bSqlErr)
	{
		if(m_api->m_ModeInteractive) {	buf=APL_T("Ошибка выполнения запроса в CaplWorkFlowManager::CreateLogicalTask\n\n"); buf+=sSql; 	AfxMessageBox(buf,MB_OK|MB_ICONSTOP);}
		return 0;
	}

	// Если это поставить после запуска следующих, то не будет работать завершение процесса
	m_data->PutAttr(task_log_el, a_task_state, _T("complete"));


	int i;
	for(i=0;i<ext_next_rel.GetSize();i++)
	{
		CaplInstance *outCon=ext_next_rel[i];
		if(0==outCon) continue;
		CaplInstance *new_activity;
		m_data->GetAttr(outCon, a_act_rel_to, new_activity);
		if(0==new_activity) continue;

		if(m_data->IsKindOf(new_activity, e_activity))
		{
			aplExtent ext;
			CaplInstance* nextTask= CreateTask(process, new_activity, outCon, ext, task_log_el, _T("medium"), _T(""), _T(""), _T(""));
		}
		else if(m_data->IsKindOf(new_activity, e_end_point)) //Процесс завершен
		{
			if(1==ext_next_rel.GetSize())
			{
				EndWfProcess(process);
			}
		}
	}
	
	if(m_AutoSave)m_api->SaveChanges();
	return 0;
}

bool CaplWorkFlowManager::StopAllProcessTask(CaplInstance *process)
{
	if(0==process) return false;
	if(process->IsDeleted()) return false ;
	if(process->GetAccessmode()>aplRW) return false ;

	// Останавливаем другие задачи
	aplExtent ext;
	CString sSql,s_curdate,buf;
	bool bSqlErr;
	sSql.Format(_T("SELECT_LOAD_ALL Ext_ FROM Ext_{apl_task(.of_process =#%i AND  ( .state='active' or .state='work' or .state='wait') )}END_SELECT"), process->GetId());

	bSqlErr=m_api->m_data.NET_QueryEditParse(sSql);
	if(bSqlErr) bSqlErr=m_api->m_data.NET_QueryExecute(ext);
	if(!bSqlErr)
	{
		if(m_api->m_ModeInteractive) {	buf=APL_T("Ошибка выполнения запроса в CaplWorkFlowManager::CreateTask/StopAnotherTask\n\n"); buf+=sSql; 	AfxMessageBox(buf,MB_OK|MB_ICONSTOP);}
		return 0;
	}
	int i;

	COleDateTime odt;
	m_api->m_data.NET_GetServerDateTime(odt);
	CString server_date;
	aplDate2String(odt, server_date);

	for(i=0;i<ext.GetSize();i++)
	{
		CaplInstance *task4stop=ext[i];
		if(0==task4stop) continue;

		/*m_data->GetAttr(task4stop, a_task_state, buf);
		if(buf==_T("wait")) {m_data->PutAttr(task4stop, a_task_state, _T("suspend")); continue;} // Отключаем недосработавшие элементы "и"
		SuspendTask(task4stop,false);*/
		m_data->PutAttr(task4stop, a_act_inst_end_date, server_date);
		m_data->PutAttr(task4stop, a_task_state, _T("cancel"));
	}
	if(m_AutoSave)m_api->SaveChanges();
	return true;
}

//*******************************************************************************

bool CaplWorkFlowManager::CreateContentForTaskNotify(CString &sContent, CaplInstance *task, LPCTSTR psNotify)
{
	sContent.Empty();
	if(0!=psNotify) sContent+=psNotify;

	if(0==task) return false;

	CString sBuf, sID_p,sName_p,sTaskName,sTaskId;
	m_api->m_data.GetAttr(task, a_action_id, sTaskId);
	m_api->m_data.GetAttr(task, a_action_name, sTaskName);

	sBuf.Format(APL_T("   Задание \"%s : %s\""),LPCTSTR(sTaskId),LPCTSTR(sTaskName));
	sContent+=sBuf;

	CaplInstance *proc;
	m_api->m_data.GetAttr(task, a_task_proc, proc);

	if(0!=proc)
	{
		m_api->m_data.GetAttr(proc, a_action_id, sID_p);
		m_api->m_data.GetAttr(proc, a_action_name, sName_p);
	
		sBuf.Format(APL_T("  в процессе \"%s : %s\""),LPCTSTR(sTaskId),LPCTSTR(sTaskName),LPCTSTR(sID_p),LPCTSTR(sName_p));
		sContent+=sBuf;
	}

	sContent+=_T(".");

	return true;
}


//*******************************************************************************
CaplInstance* CaplWorkFlowManager::CreateTask(CaplInstance* process, CaplInstance* activity, CaplInstance* connector,
		aplExtent &sub_proc, CaplInstance* previous, LPCTSTR priority,
		LPCTSTR id, LPCTSTR name, LPCTSTR dscr,
		CaplInstance* performer, CaplInstance* manager,  
		LPCTSTR start_date, LPCTSTR finish_date, LPCTSTR check_date)
{
	CaplInstance* task= NULL;
	
	if(!m_data || !m_data->IsConnected()) return task;
	if(process==NULL) return task;
	if(activity==NULL) return task;


	LoadProcessInfo(process);
	LoadActivityInfo(activity);

	bool bStopAnotherTask=false;
	m_data->GetAttr(activity, a_activity_stop_another_task, bStopAnotherTask);
	if(bStopAnotherTask) StopAllProcessTask(process);

	if(IsItemLogicalElement(activity)) return CreateLogicalTask(process,activity,connector, sub_proc,previous);

	CString buf;
	CaplInstance* taskProt= NULL, *inst= NULL;
	CaplInstance* process_prot;
	
	aplExtent taskProts;
	m_data->GetAttr(process, a_proc_process_prot, process_prot);
	if(process_prot)
	{
		GetProcessPrototypeItems(process_prot, taskProts);
	}
	else
	{
		m_data->GetAttr(process, a_proc_task_prot, taskProts);		
	}

	for(int i= 0; i<taskProts.GetSize(); i++)
	{
		m_api->m_data.GetAttr(taskProts[i], a_task_tmpl_activity, inst);
		if(inst==activity)
		{
			taskProt= taskProts[i];
			break;
		}
	}
	
	COleDateTime odt;
	m_api->m_data.NET_GetServerDateTime(odt);
	COleDateTimeSpan odts;

	CString sId, sName, sDscr, sState= _T("inactive");

	
	sId= id;
	sName= name;
	sDscr= dscr;

	double rDur= 0;
	aplExtent ext, aeRoles;
	CString dS, dF, dC;
	CaplInstance *pMgr= NULL, *pPer= NULL;

	CaplLoadData ld(m_data,DEF_SOURCE);
	int ii= ld.AddQuery(-1,activity,true);

	if(!ld.LoadEx())
	{
		if(m_api->m_ModeInteractive)
			if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
				AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
	}
	
	if(sId.IsEmpty())
		sId= odt.Format(_T("%Y.%m.%d %H:%M:%S"));

	if(m_api->m_options_mgr.CheckInstallCode(APL_NO_T("Созвездие")))
	{
		CString sPrcId;
		m_data->GetAttr(process, a_action_id, sPrcId);
		if(sPrcId!=_T(""))
		{
			sPrcId+=_T(" "); sPrcId+=sId;
			sId=sPrcId;
		}
	}

	if(sName.IsEmpty())
	{
		if(taskProt)
			m_data->GetAttr(taskProt, a_task_tmpl_name, sName);
		else 
			m_data->GetAttr(activity, a_action_name, sName);
	}

	int iVal;
	m_api->m_options_mgr.GetOptionValueBN(APL_NO_T("Настройка Workflow\\Добавлять наименование процесса в наименование задания"), iVal, 0);
	if(1==iVal)
	{
		m_data->GetAttr(process, a_action_name, buf);
		sName= sName+_T(" (")+buf+_T(")");
	}

	m_data->GetAttr(activity, a_activity_duration, rDur);
	
	pPer= performer;
	pMgr= manager;
	if(taskProt)
	{
		m_data->GetAttr(taskProt, a_task_tmpl_duration, rDur);
		if(0==rDur) m_data->GetAttr(activity, a_activity_duration, rDur);

		if(!pMgr) m_data->GetAttr(taskProt, a_task_tmpl_manager, pMgr);
		if(!pPer) m_data->GetAttr(taskProt, a_task_tmpl_performer, pPer);

		sState= _T("active");
	}
	
	//выдача задания владельцу процесса
	if(!pPer)
	{
		bool bGiveTheProcessOwner=false; 
		m_api->m_data.GetAttr(activity, a_activity_give_the_process_owner, bGiveTheProcessOwner);
		if(bGiveTheProcessOwner)
			m_data->GetAttr(process, a_proc_owner, pPer);
	}

	if(!pMgr && !pPer)
	{
		aplExtent performers, managers;
		m_api->m_data.GetAttr(activity, a_activity_executors, performers);
		m_api->m_data.GetAttr(activity, a_activity_managers, managers);
		
		if(1==performers.GetSize() &&
			(m_api->m_data.IsKindOf(performers[0], m_api->m_appr_mgr.e_person)||
				m_api->m_data.IsKindOf(performers[0], m_api->m_appr_mgr.e_official)))
					pPer= performers[0];
		else if(1==managers.GetSize() && 
			(m_api->m_data.IsKindOf(managers[0], m_api->m_appr_mgr.e_person)||
				m_api->m_data.IsKindOf(managers[0], m_api->m_appr_mgr.e_official)))
					pMgr= managers[0];
	}

	////////////////
	//Вычисление дат
	dS= start_date;
	dF= finish_date;
	dC= check_date;

	if(start_date==_T(""))
		aplDate2String(odt, dS);

	if(rDur!=0)
	{
		/*odts.m_span= rDur;
		odts.SetStatus(COleDateTimeSpan::valid);
		odt+=odts;
		if(finish_date==_T(""))
			aplDate2String(odt, dF);

		odt-=odts;
		odts.m_span= rDur*2/3;
		odt+=odts;
		if(check_date==_T(""))
			aplDate2String(odt, dC);*/

		// ЯАИ 10.10.2011:  замена предыдущего
		m_api->m_appr_mgr.LoadHolydaysInCash();
		COleDateTime odt_check,odt_finish;
		FillWfDates(odt,rDur,odt_check,odt_finish);
		aplDate2String(odt_finish, dF);
		aplDate2String(odt_check, dC);

	}
	////////////////
	CString sErrorDescr;

	task= m_data->CreateInstance(e_task);	
	if(task)
	{	
		m_data->PutAttr(task, a_task_proc, process);
		m_data->PutAttr(task, a_task_activity, activity);
		m_data->PutAttr(task, a_task_sub_proc, sub_proc);
		m_data->PutAttr(task, a_task_prev, previous);

		m_data->PutAttr(task, a_action_id, sId);
		m_data->PutAttr(task, a_action_name, sName);
		m_data->PutAttr(task, a_action_dscr, sDscr);
		
		m_data->PutAttr(task, a_task_manager, pMgr);
		m_data->PutAttr(task, a_task_performer, pPer);
		
		m_data->PutAttr(task, a_act_inst_start_date, dS);
		m_data->PutAttr(task, a_act_inst_finish_date, dF);
		m_data->PutAttr(task, a_act_inst_check_date, dC);

		CaplInstance *process_template;
		apidata.GetAttr(process,a_proc_of_tmpl, process_template);
		if(0!=process_template)
		{
			bool b_set_enddate_by_task;
			apidata.GetAttr(process_template, a_proc_tmpl_set_enddate_by_task, b_set_enddate_by_task);
			if(b_set_enddate_by_task)
			{
				apidata.PutAttr(process, a_act_inst_finish_date, dF);

				CString buf2;
				apidata.GetAttr(task, a_act_inst_check_date, buf2);
				if(buf2==_T("") && dF!=_T("")) 
				{
					COleDateTime odt; aplString2Date(dF,odt);
					COleDateTimeSpan odts(0,1,0,0);
					odt-=odts;
					aplDate2String(odt,buf2);
				}
				apidata.PutAttr(process, a_act_inst_check_date, buf2);
			}
		}
		
		if((!dS.IsEmpty() &&  (pMgr || pPer))) // задана начальная дата и исполнители
		{
			sState= _T("active");
			
			if(dS!=_T("") && dF!=_T("") && dF<dS) // но даты заданы криво
				{ sState= _T("inactive");  sErrorDescr=APL_T("(Дата начала меньше даты окончания.)");}
			if(dS!=_T("") && dF!=_T("") && dC!=_T("") && !(dS<dC && dC<=dF))
				{sState= _T("inactive");  sErrorDescr=APL_T("(Контрольная дата вне диапазона дат начала и окончания.)");}
//		}
//		if(sState==_T("active"))
//		{
			if(activity)
			{
				m_data->GetAttr(activity, a_activity_st_mode, buf);
				if(buf==_T("manual")) { sState= _T("inactive"); sErrorDescr=APL_T("(Установлен ручной запуск.)");}
			}
		}	

		m_data->PutAttr(task, a_task_state, sState);

		//ЯАИ - меняем состояние процесса
		CString sProcStatate=_T("running");
		if(sState!=_T("active")) sProcStatate=_T("jammed");
		m_data->PutAttr(process, a_proc_state, sProcStatate);


		m_data->GetAttr(process, a_act_inst_prior, buf);// по фигу, что пришло...
//		m_data->PutAttr(task, a_act_inst_prior, priority);
		m_data->PutAttr(task, a_act_inst_prior, buf);		
		if(m_AutoSave)
		{
			m_api->SaveChanges();
			aplExtent extAccess;
			extAccess.Add(task);
			m_api->m_data.NET_SetInstancesAccess(&extAccess, (CaplInstance*)-1, aplRW, APL_T("Установка доступа \"Чтение-запись\"..."));	
		}
		
		if(sState==_T("active"))
		{
			//Message
			CaplInstance *Recipient=pPer;
			if(0==Recipient)Recipient=pMgr;

			if(CheckPersonNotify(m_api,Recipient,_T("#NewTaskNotify")))
			{
				CString sSubject, sContent;
				CaplInstance *owner= NULL, *inst= NULL;

				CaplInstance *CurPerson=m_api->m_appr_mgr.GetCurrentPerson();

				sSubject= APL_T("Новое задание");
				//sContent= APL_T("Вы получили задание.");
				//sContent.Format(APL_T("Вы получили задание \"%s : %s\"  в процессе \"%s : %s\""),LPCTSTR(sTaskId),LPCTSTR(sTaskName),LPCTSTR(sID_p),LPCTSTR(sName_p));
				CreateContentForTaskNotify(sContent, task, APL_T("Вы получили задание."));
				
				aplExtent ext;
				ext.Add(task);
				m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), Recipient, sSubject, sContent, ext,1,_T("sendet"),false,true);
			}
			if(sState==_T("active"))
			{
				CaplInstance* connector= NULL;
				aplExtent checkedItems;

				if(FALSE==RunProgrammModule(task, checkedItems, connector, true))
				{
	// 				if(m_api->m_ModeInteractive)
	// 					AfxMessageBox(APL_T("Не удалось выполнить дополнение запуска задания."), MB_ICONERROR|MB_OK);
	// 				sState= _T("inactive");
					return task;
				}
			}		
		}
		else
		{
			CaplInstance* curPerson= m_api->m_appr_mgr.GetCurrentPerson();
			if(curPerson)
			{				
				CaplInstance *owner, *manager;
				m_api->m_data.GetAttr(process, a_proc_owner, owner);
				m_api->m_data.GetAttr(process, a_proc_manager, manager);

				buf=APL_T("Задание не удалось выдать автоматически.\n"); buf+=sErrorDescr; buf+=APL_T("\n\nВы хотите настроить параметры задания вручную?");
				
				if((curPerson==owner||curPerson==manager) && m_api->m_ModeInteractive && 
					IDYES==AfxMessageBox(buf, MB_OK|MB_YESNO))
					ShowTaskProperties(task);
				
				CaplInstance*task_performer,*task_manager;
				m_api->m_data.GetAttr(task, a_task_performer, task_performer);
				m_api->m_data.GetAttr(task, a_task_manager, task_manager);
				if(0==task_performer && 0==task_performer) // Нет ни исполнителя ни координатора
				{
					// Отправляем сообщение

					ext.Add(process);

					CString sSubject, sContent;
					CString sID_p,sName_p;

					m_api->m_data.GetAttr(process, a_action_id, sID_p);
					m_api->m_data.GetAttr(process, a_action_name, sName_p);
					sSubject.Format(APL_T("Уведомление об остановке процесса  %s:%s"), sID_p, sName_p);
					sContent.Format(APL_T("Остановлен процесс  \"%s\":\"%s\"   - не задан исполнитель задания"), sID_p, sName_p);

					CaplInstance *owner,*mgr;
					m_api->m_data.GetAttr(process, a_proc_owner, owner);
					m_api->m_data.GetAttr(process, a_proc_manager, mgr);

					// Эти сообщения отсылаются независимо от настроек
					if(0!=owner && owner!=curPerson) m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), owner, sSubject, sContent, ext,1,_T("sendet"),false,true);
					if(0!=mgr   &&  mgr!=curPerson && mgr!=owner)  m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), mgr,   sSubject, sContent, ext,1,_T("sendet"),false,true);
				}
			}											
		}		
	}

	return task;
}
//*******************************************************************************
bool CaplWorkFlowManager::RunTask(CaplInstance* task, bool bVerify)
{
	if(m_data==NULL) return false;
	if(task==NULL) return false;
	if(task->GetId()==0) return false;
	if(e_task==NULL) return false;

	bool bValid= true;

	CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();
	if(!user) return false;
	CaplInstance *inst= NULL;
	
	CaplInstance* owner, *mgr, *per, *procMgr;
	m_data->GetAttr(task, a_task_proc, inst);
	LoadProcessInfo(inst);

	if(IsItemLogicalElement(task)) return false;

	CString buf;

	m_data->GetAttr(inst, a_proc_owner, owner);
	m_data->GetAttr(inst, a_proc_manager, procMgr);

	if(procMgr && m_api->m_data.IsKindOf(procMgr, m_api->m_appr_mgr.e_official))
		m_api->m_data.GetAttr(procMgr, m_api->m_appr_mgr.a_official_act_person, procMgr);

	if(owner!=user && procMgr!=user && bVerify)
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Вы не можете запустить данное задание."), MB_OK|MB_ICONERROR);
		return false;
	}
	
	CString  sStDate, sEndDate, sCheckDate;
	CaplInstance* inst0= NULL;

	m_data->GetAttr(task, a_action_id, buf);
	if(buf.IsEmpty()) bValid= false;
	m_data->GetAttr(task, a_action_name, buf);
	if(buf.IsEmpty()) bValid= false;
	m_data->GetAttr(task, a_task_performer, per);
	m_data->GetAttr(task, a_task_manager, mgr);
	if(!per && !mgr)
		bValid= false;

//	m_data->GetAttr(task, a_act_inst_start_date, sStDate);
//	if(sStDate.IsEmpty()) bValid= false;
//	m_data->GetAttr(task, a_act_inst_finish_date, sEndDate);
//	if(sEndDate.IsEmpty()) bValid= false;
//	m_data->GetAttr(task, a_act_inst_check_date, sCheckDate);
//	if(sCheckDate.IsEmpty()) bValid= false;
	
	if(!sStDate.IsEmpty() && !sEndDate.IsEmpty() 
		&&  sEndDate<sStDate) bValid= false;
	if(!sEndDate.IsEmpty() && !sStDate.IsEmpty() && !sCheckDate.IsEmpty() 
		&& !(sStDate<sCheckDate && sCheckDate<sEndDate)) bValid= false;

	if(bValid)
	{
		CaplInstance* process= NULL;
		CString buf;
		m_data->GetAttr(task, a_task_proc, process);
		if(process)
		{
			m_data->GetAttr(process, a_proc_state, buf);
			if(buf==_T("suspended") && bVerify)
			{
				if(m_api->m_ModeInteractive)
					AfxMessageBox(APL_T("Вы не можете запустить данное задание.\n\nПроцесс остановен."), MB_OK|MB_ICONERROR);
				return false;
			}
		}
		m_data->GetAttr(task, a_task_state, buf);
		CString str;
		m_data->GetAttr(task, a_task_old_state, str);
		if(str.IsEmpty())
			str= _T("active");
		m_data->PutAttr(task, a_task_state, str);
		
		LoadTaskInfo(task);

		CaplAggr aggr;
		m_data->GetAttr(task, a_task_sub_proc, aggr);
		
		for(int i= 0; i<aggr.GetSize(); i++)
		{
			inst= NULL;
			aggr.GetByIndex(i, inst);
			if(inst)
			{
				LoadProcessInfo(inst);
				m_data->GetAttr(inst, a_proc_state, buf);
				if(buf==_T("suspended"))
					RunWfProcess(inst, false);  //не будет проверяться, кто может 
												//запустить процесс
			}
		}
		
		if(m_AutoSave)m_api->SaveChanges();
		
		//Message

		CaplInstance *Recipient;
		m_data->GetAttr(task, a_task_performer, Recipient);
		if(0==Recipient) m_data->GetAttr(task, a_task_manager, Recipient);


		CString sSubject, sContent, sOption;
		
		if(buf==_T("inactive"))
		{
			sOption=_T("#NewTaskNotify");
			sSubject= APL_T("Новое задание"); 
			//sContent= APL_T("Вы получили новое задание.");
			CreateContentForTaskNotify(sContent, task, APL_T("Вы получили новое задание."));
		}
		else 
		{
			sOption=_T("#RunTaskNotify");
			sSubject= APL_T("Задание"); 
			//sContent= APL_T("Ранее остановленное задание активизировано.");
			CreateContentForTaskNotify(sContent, task, APL_T("Ранее остановленное задание активизировано."));
		}
	
		if(CheckPersonNotify(m_api,Recipient,sOption))
		{
			aplExtent ext;
			ext.Add(task);
			m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), Recipient, sSubject, sContent, ext,1,_T("sendet"),false,true);
		}
	}
	else
	{
		if(m_api->m_ModeInteractive && IDYES==AfxMessageBox(APL_T("Задание не удалось выдать автоматически.\nВы хотите настроить параметры задания вручную?"), 
			MB_OK|MB_YESNO))
			ShowTaskProperties(task);
	}

	return true;
}

//*******************************************************************************
bool CaplWorkFlowManager::SetTaskWorking(CaplInstance* task)
{
	if(0==task) return false;

	CString sDate, sState;
	m_api->m_data.GetAttr(task, a_task_reseave_date, sDate);
	m_api->m_data.GetAttr(task, a_task_state, sState);

	if(sState==_T("work") && sDate!=_T("")) return true; //Уже запущено

	//текущая дата
	COleDateTime odt;
	m_api->m_data.NET_GetServerDateTime(odt);
	CString sCurDate;
	aplDate2String(odt, sCurDate);

	m_api->m_data.PutAttr(task, a_task_reseave_date, sCurDate);
	m_api->m_data.PutAttr(task, a_task_state, _T("work"));
	m_api->SaveChanges();

	aplExtent extWO;

	if(FALSE==RunProgrammModule(task, extWO))
	{
		AfxMessageBox( APL_T("Не удалось выполнить дополнение запуска задания."), MB_ICONERROR|MB_OK);
		return false; 
	}
	m_api->SaveChanges();

	return true;
}


//*******************************************************************************
CaplInstance* CaplWorkFlowManager::RestartTask(CaplInstance* task, 
										CaplInstance* newManager, CaplInstance* newPerformer)
{
	CaplInstance* newTask= NULL;

	if(m_data==NULL) return NULL;
	if(task==NULL) return NULL;
	if(task->GetId()==0) return NULL;
	if(task->GetType()==0) return NULL;
	if(e_task==NULL) return NULL;

	if(m_api->m_ModeInteractive)
	{
		if(IDYES!=AfxMessageBox(APL_T("Вы действительно хотите перезапустить  задание ?"), MB_YESNO|MB_ICONWARNING))
		return false;
	}

	
	if(m_data->IsConnected())
	{
		CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();
		if(!user) return false;
		CaplInstance *inst= NULL;
		
		CaplInstance* owner= NULL, *procMgr= NULL;
		CaplInstance* mgrInst= NULL;
		m_data->GetAttr(task, a_task_proc, inst);
		
		LoadProcessInfo(inst);

		m_data->GetAttr(inst, a_proc_owner, owner);
		m_data->GetAttr(inst, a_proc_manager, procMgr);
		if(procMgr && m_api->m_data.IsKindOf(procMgr, m_api->m_appr_mgr.e_official))
			m_api->m_data.GetAttr(procMgr, m_api->m_appr_mgr.a_official_act_person, procMgr);
		
		CaplInstance* mgr= NULL;
		m_data->GetAttr(task, a_task_manager, mgrInst);
		if(mgrInst && m_api->m_data.IsKindOf(mgrInst, m_api->m_appr_mgr.e_official))
			m_api->m_data.GetAttr(mgrInst, m_api->m_appr_mgr.a_official_act_person, mgr);
		else
			mgr= mgrInst;

		if(!m_api->m_data.IsAdmin() && owner!=user && procMgr!=user && mgr!=user)
		{
			if(m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Вы не можете перезапустить данное задание."), MB_OK|MB_ICONERROR);
			return false;
		}

		COleDateTime odt= COleDateTime::GetCurrentTime(), odtOld;
		COleDateTimeSpan odts;
		CaplInstance*act= NULL, *process= NULL, *per= NULL;
		CString sId, sName, sDscr, buf;
		
		m_data->GetAttr(task, a_task_activity, act);
		m_data->GetAttr(task, a_task_proc, process);
		m_data->GetAttr(task, a_action_dscr, sDscr);

		if(act)
		{
			aplExtent ext;
			
			inst= NULL;
			CaplInstance* inst1= NULL;
			if(mgr==user) //перезапускает задание ответственный
			{
				//newManager= mgr;
			}
			if(owner==user) //перезапускает задание владелец
			{
				
			}

			newTask= CreateTask(process, act, 0, ext, task, _T("medium"), 
				_T(""), _T(""), sDscr, newPerformer, newManager);		
			
			if(newTask)
			{
				LoadTaskInfo(task);
				CaplAggr sub_procs;
				CaplInstance* sub_proc;
				m_data->GetAttr(task, a_task_sub_proc, sub_procs);
				//Отменяем все подпроцессы
				for(int j= 0; j<sub_procs.GetSize(); j++)
				{
					sub_proc= NULL;
					sub_procs.GetByIndex(j, sub_proc);
					if(sub_proc)
					{
						LoadProcessInfo(sub_proc);
						CString str;
						m_data->GetAttr(sub_proc, a_proc_state, str);
						if(str!=_T("completed") && str!=_T("terminated"))
							TerminateWfProcess(sub_proc, false);
					}
				}				
				m_api->m_data.NET_GetServerDateTime(odt);
				aplDate2String(odt, buf);
				m_data->PutAttr(task, a_act_inst_end_date, buf);
				m_data->PutAttr(task, a_task_state, _T("cancel"));
			}
			else
			{
				//Все удалить...
				m_data->DeleteInstance(newTask);
			}
			if(m_AutoSave)m_api->SaveChanges();
		}
	}

	return newTask;
}
//*******************************************************************************
bool CaplWorkFlowManager::SuspendTask(CaplInstance* task, bool bVerify)
{
	if(m_data==NULL) return false;
	if(task==NULL) return false;
	if(task->GetId()==0) return false;
	if(task->GetType()==0) return false;
	if(e_task==NULL) return false;

	CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();
	if(!user) return false;
	CaplInstance *inst= NULL;
	
	CaplInstance* owner= NULL, *procMgr= NULL;
	m_data->GetAttr(task, a_task_proc, inst);
	LoadProcessInfo(inst);
	m_data->GetAttr(inst, a_proc_owner, owner);
	m_data->GetAttr(inst, a_proc_manager, procMgr);
	if(procMgr && m_api->m_data.IsKindOf(procMgr, m_api->m_appr_mgr.e_official))
		m_api->m_data.GetAttr(procMgr, m_api->m_appr_mgr.a_official_act_person, procMgr);

	CaplInstance* mgr= NULL, *per= NULL;
	m_data->GetAttr(task, a_task_manager, mgr);
	
	CString buf;
	if(owner!=user && procMgr!=user && bVerify)
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Вы не можете остановить данное задание."), MB_OK|MB_ICONERROR);
		return false;
	}

	m_data->GetAttr(task, a_task_state, buf);
	m_data->PutAttr(task, a_task_old_state, buf);
	m_data->PutAttr(task, a_task_state, _T("suspend"));
	
	CaplAggr aggr;
	m_data->GetAttr(task, a_task_sub_proc, aggr);
	
	for(int i= 0; i<aggr.GetSize(); i++)
	{
		inst= NULL;
		aggr.GetByIndex(i, inst);
		if(inst)
		{
			LoadProcessInfo(inst);
			m_data->GetAttr(inst, a_proc_state, buf);
			if(buf==_T("running"))
				SuspendWfProcess(inst, false);
		}
	}

	if(m_AutoSave)m_api->SaveChanges();

	//Message
	{
		CaplInstance* mgr= NULL, *per= NULL;	
		CString sSubject, sContent;
	
		{
			CaplInstance *Recipient;
			m_data->GetAttr(task, a_task_performer, Recipient);
			if(0==Recipient )m_data->GetAttr(task, a_task_manager, Recipient);
			
			if(CheckPersonNotify(m_api,Recipient,_T("#SuspendTaskNotifyExecutor")))
			{
				aplExtent ext;
				ext.Add(task);
				sSubject= APL_T("Задание остановлено");
				//sContent= APL_T("Выданное Вам ранее задание остановлено.");
				CreateContentForTaskNotify(sContent, task, APL_T("Выданное Вам ранее задание остановлено."));
				m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), Recipient, sSubject, sContent, ext,1,_T("sendet"),false,true);
			}
		}

		{
			sSubject= APL_T("Задание в Вашем процессе остановлено"); 
			//sContent= APL_T("Остановлено задание в процессе");
			CreateContentForTaskNotify(sContent, task, APL_T("Остановлено задание в процессе"));
			CaplInstance *proc;
			m_data->GetAttr(task, a_task_proc, proc);
			LoadProcessInfo(proc);

			aplExtent ext;
			ext.Add(proc);

			if(CheckPersonNotify(m_api,owner,_T("#SuspendTaskNotifyOwner")))  m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), owner,   sSubject, sContent, ext,1,_T("sendet"),false,true);
			if(CheckPersonNotify(m_api,procMgr,_T("#SuspendTaskNotifyOwner"))) m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), procMgr, sSubject, sContent, ext,1,_T("sendet"),false,true);
		}
	}

	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::EndTask(CaplInstance* task, CaplInstance* connector, bool bCancelTask, bool bForce)
{
	if(m_data==NULL) return false;
	if(task==NULL) return false;
	if(task->GetId()==0) return false;
	if(task->GetType()==0) return false;
	if(e_activity==NULL) return false;
	if(e_task==NULL) return false;
	if(e_proc_tmpl==NULL) return false;
	if(e_proc==NULL) return false;
	
	CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();
	aplExtent officials;
	m_api->m_appr_mgr.GetPersonOfficials(user, officials);
	CaplInstance *inst= NULL;
	
	CaplInstance* inst1= NULL, *inst2= NULL, *owner= NULL, *mgr= NULL, *per= NULL;
	m_data->GetAttr(task, a_task_performer, per);
	m_data->GetAttr(task, a_task_proc, inst);
	if(inst)
	{
		LoadProcessInfo(inst);
		m_data->GetAttr(inst, a_proc_owner, owner);
	}

	if(!bCancelTask)
	{
		#ifdef _DEBUG
			if(user!=per && user!=owner && -1==officials.Find(per))
		#else 
			if(user!=per && -1==officials.Find(per)) 
		#endif
			{
				if(!bForce)
				{
					if(m_api->m_ModeInteractive)
						AfxMessageBox(APL_T("Завершить задание может только исполнитель."), MB_OK|MB_ICONERROR);
					return false;
				}
			}
	}

	CaplAggr aggr;
	CString state;
	bool bShowMsg = true;

	m_data->GetAttr(task, a_task_sub_proc, aggr);
	for(int i= 0; i<aggr.GetSize(); i++)
	{
		inst= NULL;
		aggr.GetByIndex(i, inst);
		if(inst)
		{
			LoadProcessInfo(inst);
			state= _T("");
			m_data->GetAttr(inst, a_proc_state, state);
			if(state!=_T("terminated") && state!=_T("completed"))
			{
				if(!bCancelTask)
				{
					if(m_api->m_ModeInteractive)
						AfxMessageBox(APL_T("Подпроцессы задания не выполнены до конца.\n\nЗадание не может быть завершено"), MB_OK|MB_ICONERROR);
					return false;
				}
				else
				{
					if(bShowMsg)
					{
						if(m_api->m_ModeInteractive && AfxMessageBox(APL_T("Некоторые подпроцессы задания не завершены, желаете завершить их?"), MB_ICONQUESTION|MB_YESNO) == IDNO)
							return false;						
					}
					
					aplExtent aeTasks;
					GetProcessTasks(inst, aeTasks);

					for(int j=0; j<aeTasks.Size; ++j) EndTask(aeTasks[j], NULL, true);
					EndWfProcess(inst);				
					bShowMsg = false;
				}
			}
		}
	}	

	if(m_data->IsConnected())
	{
		CaplInstance* inst= NULL;
		CaplInstance *outCon= NULL, *activity= NULL, *prot= NULL,
			*proc= NULL,
			*stDate= NULL, *fnDate= NULL, *chDate= NULL;
		aplExtent ext_in, ext_out, ext_act, ext_ep;
		double rDur= 0;
		CString buf, sNotes;
		COleDateTime odt;
		COleDateTimeSpan odts;

		GetConnectors(task, ext_in, ext_out);
		if(connector)
		{
			if(-1==ext_out.Find(connector))
			{
				if(m_api->m_ModeInteractive)
					AfxMessageBox(APL_T("Указан переход не текущего действия. Выберите переход вручную."), MB_OK|MB_ICONERROR);
				return false;
			}
			else
				outCon= connector;
		}
		
		if(!outCon && !bCancelTask)
		{
			//////////////////////////////////////////////////////
			//Надо как-то получить переход...
			CaplSetResourceHandle setres(module_inst);
			CCommonETDialog dlg;

			dlg.m_woItems.Append(ext_out);
			dlg.m_task= task;
			dlg.m_api= m_api;
			dlg.m_wf_mgr= this;
			if(IDOK==dlg.DoModal())
			{
				outCon= dlg.m_connector;
				sNotes= dlg.m_sComents;
			}
			else
			{
				return false;
			}
		}
		/*else
		{
			if(outCon && FALSE==RunProgrammModule(task, ext_out, outCon, false))
			{
				AfxMessageBox(APL_T("Не удалось выполнить дополнение завершения задания."), MB_ICONERROR|MB_OK);
				return false; 
			}
		}*/

		//Завершение действия
		m_api->m_data.NET_GetServerDateTime(odt);
		aplDate2String(odt, buf);
		
		if(bCancelTask) m_data->PutAttr(task, a_task_state, _T("cancel"));
		else m_data->PutAttr(task, a_task_state, _T("complete"));

		m_data->PutAttr(task, a_act_inst_end_date, buf);

		double dbl= 100;			
		m_data->PutAttr(task, a_act_inst_percent, dbl);
		
		if(m_api->m_AutoSave)m_api->SaveChanges();
		
		//Message
		CaplInstance *CurPerson=m_api->m_appr_mgr.GetCurrentPerson();
		CString sSubject, sContent;

		{
			CaplInstance *Recipient;
			m_data->GetAttr(task, a_task_performer, Recipient);
			if(0==Recipient) m_data->GetAttr(task, a_task_manager, Recipient);
			if(CheckPersonNotify(m_api,Recipient,_T("#CompleteTaskNotifyExecutor")))
			{
				aplExtent ext;
				ext.Add(task);
				sSubject= APL_T("Задание выполнено");
				//sContent= APL_T("Выданное Вам ранее задание выполнено.");
				CreateContentForTaskNotify(sContent, task, APL_T("Выданное Вам ранее задание выполнено."));
				m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), Recipient, sSubject, sContent, ext,1,_T("sendet"),false,true);
			}
		}

		{
			CaplInstance *proc,*own;
			m_data->GetAttr(task, a_task_proc, proc);
			LoadProcessInfo(proc);
			m_data->GetAttr(proc, a_proc_owner, own);
			if(CheckPersonNotify(m_api,own,_T("#CompleteTaskNotifyOwner")))
			{
				CString sID_p,sName_p,sTaskName,sTaskId;
				m_api->m_data.GetAttr(task, a_action_id, sTaskId);
				m_api->m_data.GetAttr(task, a_action_name, sTaskName);
				m_api->m_data.GetAttr(proc, a_action_id, sID_p);
				m_api->m_data.GetAttr(proc, a_action_name, sName_p);
				sSubject.Format(APL_T("Выполнено задание \"%s\"  в Вашем процессе \"%s : %s\""),LPCTSTR(sTaskName),LPCTSTR(sID_p),LPCTSTR(sName_p));
				sContent.Format(APL_T("Выполнено задание \"%s : %s\"  в Вашем процессе \"%s : %s\""),LPCTSTR(sTaskId),LPCTSTR(sTaskName),LPCTSTR(sID_p),LPCTSTR(sName_p));
				aplExtent ext;
				ext.Add(proc);

				m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), own, sSubject, sContent, ext,1,_T("sendet"),false,true);
			}
		}

		///////////////////////////////////////////////////////		
		
		m_data->GetAttr(task, a_task_proc, proc);
		if(outCon) m_data->GetAttr(outCon, a_act_rel_to, activity);

		//
		if(activity)
		{
			if(m_data->IsKindOf(activity, e_activity))
			{
				aplExtent ext;
				CaplInstance* nextTask= CreateTask(proc, activity, outCon, ext, task, _T("medium"), _T(""), _T(""), sNotes);
			}
			else if(m_data->IsKindOf(activity, e_end_point)) //Процесс завершен
			{
				EndWfProcess(proc);				
			}
			else if(m_data->IsKindOf(activity, e_start_point))
			{
				
			}
		}
	}
	
	return true;
}

//*******************************************************************************
bool CaplWorkFlowManager::ReEndTask(CaplInstance* task, CaplInstance* connector, bool bCancelTask, bool bForce)
{
	if(m_data==NULL) return false;
	if(task==NULL) return false;
	if(task->GetId()==0) return false;
	if(task->GetType()==0) return false;
	if(e_activity==NULL) return false;
	if(e_task==NULL) return false;
	if(e_proc_tmpl==NULL) return false;
	if(e_proc==NULL) return false;
	
	CaplInstance *curPerson= m_api->m_appr_mgr.GetCurrentPerson();
	aplExtent officials;
	m_api->m_appr_mgr.GetPersonOfficials(curPerson, officials);

	LoadTaskInfo(task);
	
	CString state;
	m_data->GetAttr(task, a_task_state, state);
	if(state!=_T("complete"))
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Функция доступна только для выполненных заданий!"), MB_OK|MB_ICONERROR);

		return false;
	}

	CaplInstance *process= NULL;
	m_data->GetAttr(task, a_task_proc, process);
	if(0==process) return false;
	LoadProcessInfo(process);
	
	m_data->GetAttr(process, a_proc_state, state);
	if(state!=_T("running"))
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Функция доступна только для выполняемых процессов!"), MB_OK|MB_ICONERROR);
		return false;
	}

	//if(!IsAdmin())
	{
		CaplInstance *owner, *manager;
		m_api->m_data.GetAttr(process, a_proc_owner, owner);
		m_api->m_data.GetAttr(process, a_proc_manager, manager);
		if(! (curPerson==owner||curPerson==manager))
		{
			if(m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Вы не являетесь владельцем или менеджером процесса!"), MB_OK|MB_ICONERROR);
			return false;
		}
	}

	// У процесса не должно быть выполняемых заданий
	aplExtent proctasks;
	if(GetProcessTasks(process,proctasks))
	{
		CString state;
		for(int i=0;i<proctasks.GetSize();i++)
		{
			m_data->GetAttr(proctasks[i], a_task_state, state);
			if(state==_T("active") || state==_T("work"))
			{
				if(m_api->m_ModeInteractive)
					AfxMessageBox(APL_T("У процесса не должно быть выполняемых заданий!"), MB_OK|MB_ICONERROR);
				return false;
			}
		}
	}

	if(!m_data->IsConnected()) return false;
	
	//Надо как-то получить переход...
	CaplSetResourceHandle setres(module_inst);
	CSelConnectorDlg dlg;
	dlg.m_task= task;
	dlg.m_api= m_api;
	dlg.m_wf_mgr= this;

	if(IDOK!=dlg.DoModal())return false;

	CaplInstance *outCon= dlg.m_connector;

	if(0==outCon)return false;

	CaplInstance *activity;
	if(outCon) m_data->GetAttr(outCon, a_act_rel_to, activity);
	if(0==activity) return false;
	
	if(m_data->IsKindOf(activity, e_activity))
	{
		aplExtent ext;
		CaplInstance* nextTask= CreateTask(process, activity, outCon, ext, task, _T("medium"), _T(""), _T(""), _T(""));
	}
	else if(m_data->IsKindOf(activity, e_end_point)) //Процесс завершен
	{
		EndWfProcess(process);				
	}
	else if(m_data->IsKindOf(activity, e_start_point))
	{
		
	}
	
	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::LoadTaskInfo(CaplInstance* task)
{
	aplExtent ext;
	ext.Add(task);
	return LoadTaskInfo(ext);
}

bool CaplWorkFlowManager::LoadTaskInfo(aplExtent& tasks)
{
	if(!m_api || !m_api->m_data.IsConnected()) return false;
	if(e_task==0) return false;

	CaplLoadData ld(m_data,DEF_SOURCE);	

	for(int i= 0; i<tasks.GetSize(); i++)
	{
		if(tasks[i] && tasks[i]->GetId() && tasks[i]->GetType()) ld.AddQuery(0, tasks[i], true);


		if( (i== (tasks.GetSize()-1)) ||   ld.m_queries.GetSize()>m_MaxItemsLoad)
		{
			int i1= ld.AddQuery(_T('d'), 0, 0, a_task_activity, true, true);
			ld.AddQuery(_T('d'), i1, 0, a_act_tmpl_proc_tmpl, true, true);
			ld.AddQuery(_T('d'), 0, 0, a_task_proc, true, true);

			if(!ld.LoadEx())
			{
				if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
				{
					if(m_api->m_ModeInteractive) AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
				}
			}
			ld.ClearQuery();
		}
	}
	return true;
}

//*******************************************************************************
bool CaplWorkFlowManager::LoadActivityInfo(aplExtent& activity)
{
	if(!m_api || !m_api->m_data.IsConnected()) return false;
	if(e_activity==0) return false;

	CaplLoadData ld(m_data,DEF_SOURCE);	
	for(int i= 0; i<activity.GetSize(); i++)
	{
		if(activity[i]==0)  continue;
		if(activity[i]->GetId()==0) continue;
		if(activity[i]->GetType()==0) continue;
		
		ld.AddQuery(0,activity[i], true);
	}

	if(!ld.m_queries.GetSize()) return true;

	if(!ld.LoadEx())
	{
		if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
		{
			if(m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
			return false;
		}
	}
	
	return true;
}

bool CaplWorkFlowManager::LoadActivityInfo(CaplInstance* activity)
{
	aplExtent ext;
	ext.Add(activity);
	return LoadActivityInfo(ext);
}

bool CaplWorkFlowManager::ShowTaskProperties(CaplInstance* task)
{
	if(m_data==NULL || !m_data->IsConnected()) return false;
	if(task==NULL) return false;
	if(task->GetId()== 0) return false;
	if(task->GetType()== 0) return false;

	CaplSetResourceHandle setres(module_inst);

	CTaskDlg dlg;
	dlg.m_api= m_api;
	dlg.m_wf_mgr= this;
	dlg.m_task= task;
	dlg.m_sTitle= APL_T("Свойства задания");

	CaplInstance *oldPerformer=0;
	if(task) m_api->m_data.GetAttr(task, a_task_performer, oldPerformer);
	
	int nResult = dlg.DoModal();
	if(IDOK == nResult)
	{
		if(dlg.m_lRestart==0)
		{
			if(dlg.m_lAction==1) RunTask(task);
			else if(dlg.m_lAction==2) SuspendTask(task);
			else if(dlg.m_lAction==4) EndTask(task);
			else if(dlg.m_lAction==16) 
			{
				SetTaskWorking(task);
				if(m_AutoSave)m_api->SaveChanges();
			}

			// Проверка смены исполнителя для отправки уведомления
			if(task)
			{
				CaplInstance *newPerformer=0;
				m_api->m_data.GetAttr(task, a_task_performer, newPerformer);

				if(0!=newPerformer && newPerformer!=oldPerformer)
				{
					if(CheckPersonNotify(m_api,newPerformer,_T("#NewTaskNotify")))
					{
						CString sSubject, sContent;
						CaplInstance *owner= NULL, *inst= NULL;

						//CaplInstance *CurPerson=m_api->m_appr_mgr.GetCurrentPerson();

						sSubject= APL_T("Новое задание");
						//sContent= APL_T("Вы назначены исполнителем задания.");
						CreateContentForTaskNotify(sContent, task, APL_T("Вы назначены исполнителем задания."));
						
						aplExtent ext;
						ext.Add(task);
						m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), newPerformer, sSubject, sContent, ext,1,_T("sendet"),false,true);
					}
				}
			}
		}
		else
			RestartTask(task, dlg.m_newManager, dlg.m_newPerformer);
	}
	return nResult==IDOK?true:false;
}

bool CaplWorkFlowManager::ForwardTaskToPerfomer(CaplInstance* task, CaplInstance* perfomer)
{
	bool bRes= false;
	
	return bRes;
}
//*******************************************************************************
bool CaplWorkFlowManager::GetConnectors(CaplInstance* task_or_act, aplExtent& in_con, aplExtent& out_con)
{
	bool bRes= false;	
		
	in_con.Clear();
	out_con.Clear();
	
	if(m_data== NULL) return bRes;
	if(task_or_act==NULL) return bRes;
	if(task_or_act->GetId()==0) return bRes;
	if(task_or_act->GetType()==0) return bRes;

	if(m_data->IsConnected())
	{
		CaplInstance* inst= NULL, *item= NULL;
		
		if(m_data->IsKindOf(task_or_act, e_task))
			m_data->GetAttr(task_or_act, a_task_activity, item);
		else if(m_data->IsKindOf(task_or_act, e_activity) ||
			m_data->IsKindOf(task_or_act, e_end_point) ||
			m_data->IsKindOf(task_or_act, e_start_point))
			item= task_or_act;
		else return bRes;
/*		
		if(!inst) return bRes;
		if(inst->type==0) return bRes;
		if(inst->id==0) return bRes;
*/
		CaplLoadData ld(m_data,DEF_SOURCE);
		aplExtent ext;
		int n1, n2;
		long lError= 0;
		
		n1= ld.AddQuery(_T('b'), item->GetId(), e_act_secuence, a_act_rel_from, true,true);
		n2= ld.AddQuery(_T('b'), item->GetId(), e_act_secuence, a_act_rel_to, true,true);

		if (!ld.LoadEx())
		{
			if(m_api->m_ModeInteractive)
				if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
					AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
		}
		
		bRes= m_data->GetEntityExtent(e_act_rel, ext);
		
//		CaplInstance* inst0;

		for(int i= 0; i<ext.GetSize(); ++i)
		{
			m_data->GetAttr(ext[i], a_act_rel_from, inst);
			if(item==inst) 
				out_con.Add(ext[i]);
			m_data->GetAttr(ext[i], a_act_rel_to, inst);
			if(item==inst)
				in_con.Add(ext[i]);
		}
	}

	return bRes;
}
//*******************************************************************************
bool CaplWorkFlowManager::GetProcessComponents(CaplInstance* proc_or_tmpl, 
	aplExtent& activities)
{
	bool bRes= false;
	
	activities.Clear();

	if(m_data==NULL) return bRes;
	if(proc_or_tmpl==NULL) return bRes;
	if(proc_or_tmpl->GetId()==NULL) return bRes;
	if(proc_or_tmpl->GetType()==NULL) return bRes;

	if(e_proc==NULL) return bRes;
	if(e_proc_tmpl==NULL) return bRes;
	if(e_activity==NULL) return bRes;
	if(e_end_point== NULL) return bRes;

	if(m_data->IsConnected())
	{
		CaplInstance* tmpl= NULL;
		if(m_data->IsKindOf(proc_or_tmpl, e_proc))
		{
			m_data->GetAttr(proc_or_tmpl, a_proc_of_tmpl, tmpl);
			if(tmpl==NULL) return bRes;
			if(tmpl->GetId()==0) return bRes;
			if(tmpl->GetType()==0) return bRes;
		}
		else if(m_data->IsKindOf(proc_or_tmpl, e_proc_tmpl))
		{
			tmpl= proc_or_tmpl;
		}
		else return bRes;

		CaplLoadData ld(m_data,DEF_SOURCE);
		aplExtent ext;
		int n1,n2;
		n1= ld.AddQuery(_T('b'), tmpl->GetId(), e_act_tmpl, a_act_tmpl_proc_tmpl, true,true);
			
		n2=	ld.AddQuery(_T('d'), n1, 0, a_act_tmpl_point, true, true);
		n2=	ld.AddQuery(_T('d'), n1, 0, a_act_tmpl_font, true, true);

		if (!ld.LoadEx())
		{
			if(m_api->m_ModeInteractive)
				if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
					AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
		}
		
		bRes= m_data->GetEntityExtent(e_act_tmpl, ext);
		for(int i= 0; i<ext.GetSize(); i++)
		{
			CaplInstance* inst= NULL;
			m_data->GetAttr(ext[i], a_act_tmpl_proc_tmpl, inst);
			if(inst==tmpl)	activities.Add(ext[i]);
		}

		bRes= true;
	}

	return bRes;
}
//*******************************************************************************
bool CaplWorkFlowManager::GetActivityHistory(CaplInstance* owner, 
	CaplInstance* activity, aplExtent& history)
{
	if(!m_data || !m_data->IsConnected()) return false;
	if(owner==NULL) return false;
	if(activity==NULL) return false;
	
	if(m_data->IsConnected())
	{
		CaplLoadData ld(m_data,DEF_SOURCE);
		int n;
	n=	ld.AddQuery(_T('b'), activity->GetId(), e_task, a_task_activity, true, true);
	 	ld.AddQuery(_T('d'), n, 0, a_proc_owner, true, true);
		if (!ld.LoadEx())
		{
			if(m_api->m_ModeInteractive)
				if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
					AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
		}

		aplExtent ext;
		m_data->GetEntityExtent(e_task, ext);

		CaplInstance* inst, *inst1= NULL;
		CString buf= _T("");
		for(int i= 0; i<ext.GetSize(); i++)
		{
			m_data->GetAttr(ext[i], a_task_activity, inst);
			if(inst==activity)
			{
				m_data->GetAttr(ext[i], a_task_state, buf);
				if(buf==_T("complete") || buf==_T("cancel"))
				{
					m_data->GetAttr(ext[i], a_task_proc, inst);
					if(inst) m_data->GetAttr(inst, a_proc_owner, inst1);
					if(inst1==owner)
						history.Add(ext[i]);
				}
			}
		}
	}

	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::GetUserTaskList(CaplInstance *user, aplExtent &task_list, bool bCompleted, bool bCanceled, bool bSuspended)
{
	task_list.Clear();

	if(m_data==NULL) return false;
	if(user==NULL) return false;
	if(user->GetId()==0) return false;
	if(user->GetType()==0) return false;

	bool bNew= false;

	if(m_data->IsConnected())
	{
		CString sQueryStr, sError, sState= _T(".state='active' OR .state='work'");
		if(m_api->m_show.m_task_cancel && bCanceled)sState += _T(" OR .state= 'cancel'");
		if(m_api->m_show.m_task_suspend && bSuspended)sState += _T(" OR .state= 'suspend'");
		if(m_api->m_show.m_task_complete && bCompleted)sState += _T(" OR .state= 'complete'");

		sQueryStr.Format(_T("SELECT Ext_Per OR Ext_Mgr OR Ext_OffPer OR Ext_OffMgr FROM \n")
			/*Обоненты сотрудника*/
			_T("Ext_1{apl_official.actual_person= #%i} \n")
			/*Сотрудник как исполнитель или координатор*/
			_T("Ext_Per{apl_task(.performer= #%i AND (%s))} \n")
			_T("Ext_Mgr{apl_task(.manager= #%i AND (%s))} \n")
			/*Задание для */
			_T("Ext_OffPer{apl_task(.performer IN #Ext_1 AND (%s))} \n")
			_T("Ext_OffMgr{apl_task(.manager IN #Ext_1 AND (%s))} \n")
			_T("END_SELECT"), user->GetId(), user->GetId(), sState, user->GetId(), sState, sState, sState);
		
		aplExtent ext;
		if(m_api->m_data.NET_QueryEditParse(sQueryStr, false, &sError)==true){
			m_api->m_data.NET_QueryExecute(ext, APL_T("Пожалуйста, подождите..."));
		}else{
// 			AfxMessageBox(_T("!!"));
			return false;
		}
		if(ext.GetSize())
		{
			LoadTaskInfo(ext);
			
// 			CaplLoadData ld(m_data,DEF_SOURCE);
// 			for(int j= 0; j<ext.GetSize(); j++)
// 				ld.AddQuery(0, ext[j], true);
// 
// 			if (!ld.LoadEx())
// 			{
// 				if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
// 					AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
// 			}
		}
		
		COleDateTime odt= COleDateTime::GetCurrentTime(), odtSt;
		m_api->m_data.NET_GetServerDateTime(odt);
//		CaplInstance* inst;
		CString st, buf,sProcStartDate,sCurDate;

		aplDate2String(odt,sCurDate);
		
		CaplInstance* hActivity;
		CaplInstance* hProcessTmpl; 
// 		bool bIsSysteml;

		for(int i= 0; i<ext.GetSize(); i++)
		{
			m_api->m_data.GetAttr(ext[i], a_task_activity, hActivity);
			if(!hActivity) continue;
			m_api->m_data.GetAttr(hActivity, a_act_tmpl_proc_tmpl, hProcessTmpl);
			if(!hProcessTmpl) continue;
// 			m_api->m_data.GetAttr(hProcessTmpl, a_proc_tmpl_is_system, bIsSysteml);
// 			if(bIsSysteml) continue;

			if(m_b_not_show_task_of_future_process) // Игнорировать процессы с датой запуска старше текущей
			{
				CaplInstance *proc=0;
				m_data->GetAttr(ext[i], a_task_proc, proc);
				if(proc)
				{
					m_data->GetAttr(proc, a_act_inst_start_date, sProcStartDate);
					if(sProcStartDate!=_T(""))
					{
						if(sProcStartDate>sCurDate) continue;
					}
				}
			}

			m_data->GetAttr(ext[i], a_task_state, st);
			if(st!=_T("inactive"))
			{
				CaplInstance* inst1= NULL, *inst2= NULL, *tempInst= NULL;
				m_data->GetAttr(ext[i], a_task_performer, inst1);
				if(inst1 && m_api->m_data.IsKindOf(inst1, m_api->m_appr_mgr.e_official))
				{
					m_api->m_data.GetAttr(inst1, m_api->m_appr_mgr.a_official_act_person, tempInst);
					inst1= tempInst;
				}
				m_data->GetAttr(ext[i], a_task_manager, inst2);
				if(inst2 && m_api->m_data.IsKindOf(inst2, m_api->m_appr_mgr.e_official))
				{
					m_api->m_data.GetAttr(inst2, m_api->m_appr_mgr.a_official_act_person, tempInst);
					inst2= tempInst;
				}
				if(inst1==user || inst2==user)
				{
					buf= _T("");
					m_data->GetAttr(ext[i], a_act_inst_start_date, buf);
					if(buf.IsEmpty()) continue;

					aplString2Date(buf, odtSt);
					if(odtSt<=odt)
					{
						task_list.Add(ext[i]);
						if(st==_T("active"))
						{
							m_data->GetAttr(ext[i], a_task_notify_date, buf);
							if(buf.IsEmpty())
							{
								aplDate2String(odt, buf);
								m_data->PutAttr(ext[i], a_task_notify_date, buf);
								bNew= true;
							}
						}
					}
				}
			}
		}
		if(bNew)
		{
			if(m_AutoSave) m_api->SaveChanges();
/*
			MessageBox(NULL, APL_T("Получены новые задания. \n\nНазначьте исполнителей или подтвердите получение."), 
				APL_T("Новые задания"),	MB_ICONINFORMATION | MB_OK);*/
		}
	}

	return bNew;
}
//*******************************************************************************
CaplInstance* CaplWorkFlowManager::CreateWfProcess(LPCTSTR id, LPCTSTR name, LPCTSTR dscr,
	CaplInstance* proc_tmpl, CaplInstance* owner, CaplInstance* manager,
	LPCTSTR start_date, LPCTSTR finish_date, LPCTSTR check_date,
	aplExtent &task_prot, aplExtent &work_objects, LPCTSTR priority)
{
	int i;
	CaplInstance* proc= NULL;

	if(!m_data || !m_data->IsConnected()) return proc;
	
	if(owner==NULL)
		owner= m_api->m_appr_mgr.GetCurrentPerson();
	if(owner==NULL) return NULL;
	if(owner->GetId()==0) return NULL;
	if(owner->GetType()==0) return NULL;

	if(!proc_tmpl)
	{
		aplExtent templs;
		GetUserProcessTempList(owner, templs);
		proc_tmpl= SelectTemplateSchema(templs, NULL);

	}

	if(!proc_tmpl) return NULL;
	if(proc_tmpl->GetId()==0) return NULL;
	if(proc_tmpl->GetType()==0) return NULL;	

	aplExtent holders;
	m_data->GetAttr(proc_tmpl, a_proc_tmpl_holders, holders);
	
	bool bChecked= false;

	for(i= 0; i<holders.GetSize(); i++)
	{
		if(aplIsPersonOrgElement(m_api, holders[i], owner))
		{
			bChecked= true;
			break;
		}
	}

	if(!bChecked)
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Вы не можете создать процесс по шаблону.\nВы не являетесь владельцем этого шаблона"), MB_OK|MB_ICONERROR);
		return NULL;
	}

	aplExtent aeItemsNotForWork;
	bool bValid= true;
	int ok= IDOK;

	CString sId, sName, sDscr, sPrior;
	CaplAggr protAggr, aggr;
	aplExtent woAggr, ext;
	CString sStDate, sFshDate, sChDate;
	CaplInstance* up_task= NULL, *mgr= NULL;
	CaplInstance* proc_prot= NULL;
	CaplInstance* work_obj= NULL;
	double rDuration= 0;
	COleDateTime curDate;
	
	if(id)sId= id;
	if(name)sName= name;
	if(start_date)sStDate= start_date;
	if(check_date)sChDate= check_date;
	if(finish_date)sFshDate= finish_date;

	if(sStDate.IsEmpty() && sChDate.IsEmpty() && sFshDate.IsEmpty())
		bValid= false;
	
	if(sId.IsEmpty())
	{
		m_api->m_data.NET_GetServerDateTime(curDate);
		sId= curDate.Format(_T("%Y.%m.%d %H:%M:%S"));

		if(m_api->m_options_mgr.CheckInstallCode(APL_NO_T("Созвездие")))
		{
			sId=APL_T("<Автономер>");
		}
	}

	if(sName.IsEmpty())
	{
		m_api->m_data.GetAttr(proc_tmpl, a_action_name, sName);
	}
	
	if(bValid)
	{
		sDscr= dscr;
		sPrior= priority;
		
		mgr= manager;

		for(i= 0; i<task_prot.GetSize(); i++) protAggr.Add(task_prot[i]);
		for(i= 0; i<work_objects.GetSize(); i++)
		{
			if(m_api->m_data.IsKindOf(work_objects[i], e_wo))
			{
				work_obj= work_objects[i];
			}
			else
			{
				work_obj= m_api->m_data.CreateInstance(e_wo);
				if(work_obj) m_api->m_data.PutAttr(work_obj, a_wo_object, work_objects[i]);
			}

			woAggr.Add(work_obj);
		}
	}
	else
	{
		CaplSetResourceHandle setres(module_inst);

		CProcessDlg dlg;
		dlg.m_api= m_api;
		dlg.m_wf_mgr= this;
		dlg.m_process_tmpl= proc_tmpl;
		dlg.m_process= NULL;

		dlg.m_sId= sId;
		dlg.m_sName= sName;
		dlg.m_sDscr= sDscr;
		dlg.m_sPriority= priority;
		dlg.m_sTitle= APL_T("Создание нового процесса");
		

		for(i= 0; i<work_objects.GetSize(); i++)
		{
			if(m_api->m_data.IsKindOf(work_objects[i], e_wo))
				dlg.m_wo_items.Add(work_objects[i]);
			else
				dlg.m_new_wo_items.Add(work_objects[i]);
		}
		for(i= 0; i<task_prot.GetSize(); i++) dlg.m_prot_items.Add(task_prot[i]);


		//if(m_api->m_options_mgr.CheckInstallCode(APL_NO_T("Созвездие")))
		{
			// Копируем документы в объекты для справки
			aplExtent ext_doc,ext_doc_rel;
			m_api->m_doc_mgr.FindAssociatedDocuments(proc_tmpl,ext_doc,ext_doc_rel);
			if(ext_doc.GetSize()>0) dlg.m_new_items_4_notes.Append(ext_doc);
		}
		
		int ok= dlg.DoModal();
		if(ok!=IDOK) return proc;
		else
		{
			//из диалога...
			sId= dlg.m_sId;
			if(sId==APL_T("<Автономер>")) GenerateProcId(proc_tmpl,sId);

			sName= dlg.m_sName;
			sDscr= dlg.m_sDscr;
			mgr= dlg.m_manager;
			aeItemsNotForWork.Append(dlg.m_aeItemsNotForWork);
			
			COleDateTime odt;
			odt.SetDateTime(dlg.m_d_start.GetYear(), dlg.m_d_start.GetMonth(), dlg.m_d_start.GetDay(),
				dlg.m_t_start.GetHour(),dlg.m_t_start.GetMinute(), 0);
//			m_dateMgr.Put(odt, &pStDate);
			aplDate2String(odt, sStDate);
			
			odt.SetDateTime(dlg.m_d_check.GetYear(), dlg.m_d_check.GetMonth(), dlg.m_d_check.GetDay(),
				dlg.m_t_check.GetHour(),dlg.m_t_check.GetMinute(), 0);
//			m_dateMgr.Put(odt, &pChDate);
			aplDate2String(odt, sChDate);

			odt.SetDateTime(dlg.m_d_finish.GetYear(), dlg.m_d_finish.GetMonth(), dlg.m_d_finish.GetDay(),
				dlg.m_t_finish.GetHour(),dlg.m_t_finish.GetMinute(), 0);
//			m_dateMgr.Put(odt, &pFshDate);
			aplDate2String(odt, sFshDate);
			
			protAggr.Clear(); woAggr.Clear();
			for(i=0; i<dlg.m_prot_items.GetSize(); i++) protAggr.Add(dlg.m_prot_items[i]);
			for(i= 0; i<dlg.m_wo_items.GetSize(); i++) woAggr.Add(dlg.m_wo_items[i]);

			proc_prot= dlg.m_proc_prot;

			sPrior= dlg.m_sPriority;
			up_task= dlg.m_up_level_task;
		}
	}

	proc= m_data->CreateInstance(e_proc);
	if(proc)
	{
		// аттрибуты процесса
		apidata.PutAttr(proc, a_proc_not_for_work, aeItemsNotForWork);

		m_data->PutAttr(proc, a_proc_of_tmpl, proc_tmpl);
		m_data->PutAttr(proc, a_proc_owner, owner);

		m_data->PutAttr(proc, a_action_id, sId);
		m_data->PutAttr(proc, a_action_name, sName);
		m_data->PutAttr(proc, a_action_dscr, sDscr);

		m_data->PutAttr(proc, a_act_inst_start_date, sStDate);
		m_data->PutAttr(proc, a_act_inst_finish_date, sFshDate);
		m_data->PutAttr(proc, a_act_inst_check_date, sChDate);
		
		m_data->PutAttr(proc, a_proc_manager, mgr);

		
		CaplInstance* obj= NULL, *inst= NULL;
		// Прописываем чьи это рабочие объекты (может быть не прописан)
		for(i= 0; i<woAggr.GetSize(); i++)
		{
			if(woAggr[i]) m_data->GetAttr(woAggr[i], a_wo_object, inst);
			if(!inst)
			{
				m_api->m_data.DeleteInstance(woAggr[i], false);
				continue;
			}
			
			if(woAggr[i]) m_data->PutAttr(woAggr[i], a_wo_action, proc);
			ext.Add(woAggr[i]);			
		}
		m_data->PutAttr(proc, a_proc_wo, ext);

		m_api->m_data.PutAttr(proc, a_proc_process_prot, proc_prot);
		m_api->m_data.PutAttr(proc, a_proc_task_prot, protAggr);

		m_data->PutAttr(proc, a_act_inst_prior, sPrior);
		m_data->PutAttr(proc, a_proc_state, _T("initiated"));

		if(up_task)
		{
			LoadTaskInfo(up_task);
			m_data->GetAttr(up_task, a_task_sub_proc, aggr);
			aggr.Add(proc);
			m_data->PutAttr(up_task, a_task_sub_proc, aggr);


			CString sParentName,sName;
			CaplInstance *parent_proc;
			m_api->m_data.GetAttr(up_task,a_task_proc,parent_proc);
			if(0!=parent_proc)
			{
				m_api->m_data.GetAttr(parent_proc,a_action_name,sParentName);

				if(sParentName!=_T(""))
				{
					m_api->m_data.GetAttr(proc,a_action_name,sName);
					sName+=_T(" / ");
					sName+=sParentName;
					m_api->m_data.PutAttr(proc,a_action_name,sName);
				}
			}
		}

		if(m_AutoSave)
		{
			m_api->SaveChanges();
			aplExtent extAccess;
			extAccess.Add(proc);
			m_api->m_data.NET_SetInstancesAccess(&extAccess, (CaplInstance*)-1, aplRW, APL_T("Установка доступа \"Чтение-запись\"..."));	
		}
	}

	return proc;
}
//*******************************************************************************
bool CaplWorkFlowManager::GenerateProcId(CaplInstance* process_or_template, CString &sId)
{
	sId=_T("");
	if(0==process_or_template) return false;

	CaplInstance *proc_tmpl=process_or_template;
	if(m_api->m_data.IsKindOf(proc_tmpl,e_proc)) m_api->m_data.GetAttr(proc_tmpl,a_proc_of_tmpl,proc_tmpl);
	if(!m_api->m_data.IsKindOf(proc_tmpl,e_proc_tmpl)) return false;

	COleDateTime curDate=COleDateTime::GetCurrentTime();
	CString buf;
	m_api->m_data.GetAttr(proc_tmpl, a_action_id, buf);
	sId.Format(_T("%s-%02i"),LPCTSTR(buf),curDate.GetYear()-2000);
	buf=APL_NO_T("WF\\Автономер\\"); buf+=sId;

	int num=m_api->m_options_mgr.GetCounterWithIncrementBN(buf);
	buf.Format(_T("/%04i"),num);
	sId+=buf;

	return true;
}

//*******************************************************************************
bool CaplWorkFlowManager::RunWfProcess(CaplInstance* process, bool bVerify, CaplInstance* first_activity)
{
	if(!m_data || !m_data->IsConnected()) return false;
	if(process==NULL) return false;
//	if(process->GetId()==0) return false;
	if(process->GetType()==0) return false;
	if(e_proc==NULL) return false;

	CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();
	if(!user) return false;
	
	CaplInstance* owner= NULL, *procMgr;
	m_data->GetAttr(process, a_proc_owner, owner);
	m_data->GetAttr(process, a_proc_manager, procMgr);
	if(procMgr && m_api->m_data.IsKindOf(procMgr, m_api->m_appr_mgr.e_official))
		m_api->m_data.GetAttr(procMgr, m_api->m_appr_mgr.a_official_act_person, procMgr);
	if(owner!=user && procMgr!=user && bVerify)
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Вы не можете запустить данный процесс."), MB_OK|MB_ICONERROR);
		return false;
	}
	
	CString buf;
	CaplAttrValue val[3];
	aplExtent ext0;
	
	CaplLoadData ld(m_data,DEF_SOURCE);

	val[0].value.Set(process);
	val[0].attr= a_task_sub_proc;
	m_data->NET_FindInstancesWithAttrValues(e_task, 1, &val[0], ext0, false);

	if(ext0.GetSize()>0)
	{
		LoadTaskInfo(ext0[0]);
		m_data->GetAttr(ext0[0], a_task_state, buf);
		if(buf==_T("suspend"))
		{
			if(m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Вы не можете запустить данный процесс.\n\nВышестоящее задание остановлено."), MB_OK|MB_ICONERROR);
			return false;				
		}
	}
	
	m_data->GetAttr(process, a_proc_state, buf);

	if(buf==_T("initiated"))
	{
		if(owner!=user && bVerify)
		{
			if(m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Вы не можете запустить данный процесс."), MB_OK|MB_ICONERROR);
			return false;
		}
		
		if(!first_activity)
			m_data->GetAttr(process, a_proc_first_activity, first_activity);
		
		if(!first_activity)
		{
			aplExtent acts, ep;
			aplExtent ext1, ext2;
			CaplInstance* st_point;
			
			CaplSetResourceHandle setres(module_inst);
			CStPntSelectDlg dlg;
			dlg.m_api= m_api;
			dlg.m_wf_mgr= this;
			dlg.m_process= process;

			dlg.DoModal();
			st_point= dlg.m_start_point;

			if(st_point)
			{
				GetConnectors(st_point, ext1, ext2);
				if(ext2.GetSize()>0)
					m_data->GetAttr(ext2[0], a_act_rel_to, first_activity);				
			}
		}

		if(first_activity)
		{
			if(m_data->IsKindOf(first_activity, e_activity))
			{
				aplExtent ext1;
				m_data->PutAttr(process, a_proc_first_activity, first_activity);
				m_data->GetAttr(process, a_act_inst_prior, buf);
				CaplInstance* task= CreateTask(process, first_activity, 0, ext1, NULL, buf);
			}
			else if(m_data->IsKindOf(first_activity, e_end_point))
			{
				return EndWfProcess(process);
			}
		}
		else
			return false;
	}
	else if(buf==_T("suspended"))
	{	
		aplExtent ext;
		GetProcessTasks(process, ext);
		
		for(int i= 0; i<ext.GetSize(); i++)
		{
			buf= _T("");
			m_data->GetAttr(ext[i], a_task_state, buf);
			if(buf==_T("suspend") || buf==_T("inactive"))
			{
				RunTask(ext[i], false);	//не будут проверяться, кто может запустить задание
			}
		}
	}
	else return false;

	m_data->PutAttr(process, a_proc_state, _T("running"));
	if(m_AutoSave)m_api->SaveChanges();
	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::SuspendWfProcess(CaplInstance* process, bool bVerify)
{
	bool bRes= false;
	if(!m_data || !m_data->IsConnected()) return false;
	if(process==NULL) return false;
	if(process->GetId()==0) return false;
	if(process->GetType()==0) return false;
	if(e_proc==NULL) return false;
	
	CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();
	if(!user) return false;
	CaplInstance *inst= NULL;
	
	CaplInstance* owner, *procMgr;
	m_data->GetAttr(process, a_proc_owner, owner);
	m_data->GetAttr(process, a_proc_manager, procMgr);
	if(procMgr && m_api->m_data.IsKindOf(procMgr, m_api->m_appr_mgr.e_official))
		m_api->m_data.GetAttr(procMgr, m_api->m_appr_mgr.a_official_act_person, procMgr);
	
	if(owner!=user && procMgr!=user && bVerify)
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Вы не можете остановить данный процесс."), MB_OK|MB_ICONERROR);
		return false;
	}

	CString buf;
	aplExtent ext;
	GetProcessTasks(process, ext);
	for(int i= 0; i<ext.GetSize(); i++)
	{
		buf= _T("");
		m_data->GetAttr(ext[i], a_task_state, buf);
		if(buf==_T("active") || buf==_T("work") || buf==_T("notify"))
			SuspendTask(ext[i], false);
	}

	m_data->PutAttr(process, a_proc_state, _T("suspended"));
	if(m_AutoSave)m_api->SaveChanges();
	
	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::TerminateWfProcess(CaplInstance* process, bool bVerify)
{
	if(!m_data || !m_data->IsConnected()) return false;
	if(process==NULL) return false;
	if(process->GetId()==0) return false;
	if(process->GetType()==0) return false;
	if(e_proc==NULL) return false;

	CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();
	CaplInstance* owner= NULL, *procMgr= NULL;
	CaplInstance *inst= NULL, *activity, *role;
	COleDateTime odt;
	aplExtent tasks;
	bool bEnd= true; 
	CString buf, sRole;
	int iVal;
	
	if(!user) return false;
	
	m_data->GetAttr(process, a_proc_owner, owner);
	m_data->GetAttr(process, a_proc_manager, procMgr);
	if(procMgr && m_api->m_data.IsKindOf(procMgr, m_api->m_appr_mgr.e_official))
		m_api->m_data.GetAttr(procMgr, m_api->m_appr_mgr.a_official_act_person, procMgr);
	
	if(owner!=user && procMgr!=user && bVerify)
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Вы не можете прервать данный процесс."), MB_OK|MB_ICONERROR);
		return false;
	}
	
	GetProcessTasks(process, tasks);

	CString server_date;
	m_api->m_data.NET_GetServerDateTime(odt);
	aplDate2String(odt, server_date);
	
	int i;
	for(i= 0; i<tasks.GetSize(); i++)
	{
		buf.Empty();
		m_data->GetAttr(tasks[i], a_task_state, buf);
		if(buf==_T("inactive"))
			m_data->PutAttr(tasks[i], a_task_state, _T("cancel"));
		else if(buf==_T("active") || buf==_T("suspend") ||buf==_T("work") || buf==_T("notify"))
		{
			CaplAggr sub_procs;
			CaplInstance* sub_proc;
			m_data->GetAttr(tasks[i], a_task_sub_proc, sub_procs);
			//Отменяем все подпроцессы
			for(int j= 0; j<sub_procs.GetSize(); j++)
			{
				sub_proc= NULL;
				sub_procs.GetByIndex(j, sub_proc);
				if(sub_proc)
				{
					LoadProcessInfo(sub_proc);
					CString str;
					m_data->GetAttr(sub_proc, a_proc_state, str);
					if(str!=_T("completed") && str!=_T("terminated"))
						TerminateWfProcess(sub_proc, false);
				}
			}

			m_data->PutAttr(tasks[i], a_act_inst_end_date, server_date);
			m_data->PutAttr(tasks[i], a_task_state, _T("cancel"));
			
			//Message
			//if(m_bCancelTaskNotifyExecutor||m_bCancelTaskNotifyOwner)
			{

				CaplInstance* mgr= NULL, *per= NULL;	
				CString sSubject, sContent;
				CaplInstance *task=tasks[i];

				{
					CaplInstance *Recipient;
					m_data->GetAttr(task, a_task_performer, Recipient);
					if(0==Recipient) m_data->GetAttr(task, a_task_manager, Recipient);

					if(CheckPersonNotify(m_api,Recipient,_T("#CancelTaskNotifyExecutor")))
					{
						aplExtent ext;
						ext.Add(task);
						sSubject= APL_T("Задание отозвано");
						//sContent= APL_T("Выданное Вам ранее задание отозвано.");
						CreateContentForTaskNotify(sContent, task, APL_T("Выданное Вам ранее задание отозвано."));
						m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), Recipient, sSubject, sContent, ext,1,_T("sendet"),false,true);
					}
				}

				{
					CaplInstance *proc,*parent_task;
					m_data->GetAttr(task, a_task_proc, proc);
					LoadProcessInfo(proc);
					m_data->GetAttr(proc, a_task_proc, parent_task);

					if(0!=parent_task)
					{
						LoadTaskInfo(parent_task);

						CaplInstance *Recipient;
						m_data->GetAttr(parent_task, a_task_performer, Recipient);
						if(0==Recipient)m_data->GetAttr(parent_task, a_task_manager, Recipient);

						if(CheckPersonNotify(m_api,Recipient,_T("#CancelTaskNotifyOwner")))
						{
							sSubject= APL_T("Задание в Вашем процессе отозвано"); 
							//sContent= APL_T("Отозвано задание в процессе");
							CreateContentForTaskNotify(sContent, task, APL_T("Отозвано задание в процессе."));
							aplExtent ext;
							ext.Add(proc);
							ext.Add(parent_task);
							m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), Recipient, sSubject, sContent, ext,1,_T("sendet"),false,true);
						}
					}
				}
			}
		}
	}

	m_api->m_data.NET_GetServerDateTime(odt);
	aplDate2String(odt, buf);
	m_data->PutAttr(process, a_act_inst_end_date, buf);

	m_api->m_options_mgr.GetOptionValueBN(APL_NO_T("Настройка Workflow\\Автоматически сдавать завершенные процессы в архив"), iVal, 0);
	if(iVal!=0)
		m_data->PutAttr(process, a_proc_archive_date, buf);
	m_data->PutAttr(process, a_proc_state, _T("terminated"));

#ifdef _DEBUG
 	m_api->m_options_mgr.GetOptionValueBN(APL_NO_T("Настройка Workflow\\Удалять статусы объектов при прерывании процесса"), iVal, 1);
#else
 	m_api->m_options_mgr.GetOptionValueBN(APL_NO_T("Настройка Workflow\\Удалять статусы объектов при прерывании процесса"), iVal, 0);
#endif
//	m_api->m_options_mgr.GetOptionValueBN(APL_NO_T("Настройка Workflow\\Не давать присваивать статусы рабочим объектам процесса"), iVal, 0);
	if(0!=iVal)
	{
		aplExtent items, wos, wos1, apprs, connectors, delApprs;
		aplExtent persons, statuses, roles, ext1;
		
		bool bDel;
		CaplInstance* workObj, *person;
		
		m_api->m_data.GetAttr(process, a_proc_wo, wos1);
		wos.Clear();
		
		for(i= 0; i<wos1.GetSize(); i++)
		{
			m_api->m_data.GetAttr(wos1[i], a_wo_object, workObj);
			if(workObj)wos.Add(workObj);
		}

		m_api->LoadExtentInfo(wos);

		for(i= 0; i<wos.GetSize(); i++)
		{
			workObj= wos[i];
			
			if(workObj)
			{
				if(m_api->m_data.IsKindOf(workObj, m_api->m_doc_mgr.e_apl_doc))
				{
//					m_api->m_doc_mgr.LoadDocInfo(workObj);
					m_api->m_data.GetAttr(workObj, m_api->m_doc_mgr.a_apl_doc_active, inst);
				}
				else
					inst= workObj;	
				
				if(inst) items.Add(inst);
			}
		}

		m_api->m_appr_mgr.LoadItemApproval(items, apprs);
		m_api->m_data.GetAttr(process, a_proc_of_tmpl, inst);
		GetProcessConnectors(inst, connectors);
		GetProcessComponents(inst, ext1);

		for(i= 0; i<connectors.GetSize(); i++)
		{
			m_api->m_data.GetAttr(connectors[i], a_act_secuence_status, inst);
			if(inst) statuses.Add(inst);
		}

		for(i= 0; i<tasks.GetSize(); i++)
		{
			m_api->m_data.GetAttr(tasks[i], a_task_performer, inst);
			if(inst) persons.Add(inst);

			m_api->m_data.GetAttr(tasks[i], a_task_activity, activity);
			if(!activity) continue;
			m_api->m_data.GetAttr(activity, a_activity_role, role);
			if(role) roles.Add(role);
		}

		for(i= 0; i<apprs.GetSize(); i++)
		{
			bDel= false;
			// надо что-то похитрее, если что
			m_api->m_data.GetAttr(apprs[i], m_api->m_appr_mgr.a_appr_pers_org, inst);
			if(!inst) continue;
			if(m_api->m_data.IsKindOf(inst, m_api->m_appr_mgr.e_pers_org))
				m_api->m_data.GetAttr(inst, m_api->m_appr_mgr.a_po_the_pers, person);
			else person= inst;

			if(!person) continue;
			if(-1==persons.Find(person)) continue;

			m_api->m_data.GetAttr(apprs[i], m_api->m_appr_mgr.a_appr_status, inst);
			if(-1==statuses.Find(inst)) continue;

			m_api->m_data.GetAttr(apprs[i], m_api->m_appr_mgr.a_appr_role, sRole);
			for(int j= 0; j<roles.GetSize() && !bDel; j++)
			{
				m_api->m_data.GetAttr(roles[j], m_api->m_appr_mgr.a_po_role_name, buf);
				if(0==buf.CompareNoCase(sRole)) bDel= true;
 			}
 			if(bDel) 
			{
				if(apprs[i]->GetAccessmode()>aplOWN)
					delApprs.Add(apprs[i]);
				else
					m_api->m_data.DeleteInstance(apprs[i], false);
			}
		}

		if(delApprs.GetSize())
		{
			int iSource, iResult;
			srand((unsigned)time(NULL));
			iSource= rand();
			iResult= iSource^0x7d24cf18;

			m_api->m_data.NET_SetSpecialInstancesAccess(&delApprs, m_api->m_data.GetCurrUser(),
				aplOWN, APL_T("Удаление статусов у рабочих объектов..."), iSource, iResult);

			for(i= 0; i<delApprs.GetSize(); i++)
				m_api->m_data.DeleteInstance(apprs[i], false);
		}
	}
	/*[Нахимович 30.09.2009]
		Для КВЗ: перевод состояния изменения в состояние "В разработке",
		т.к. конструктора иногда прерывают процесс не из редактора КТС*/
	//if (!sDistrCode.CompareNoCase(_T("KVZ")))
	if(m_api->m_options_mgr.CheckInstallCode(_T("KVZ")))
	{
		CString sTmplId;
		CString sState;

		aplExtent changes, wobj;
		CaplInstance* proc_tmpl;
		CaplInstance* change;
		aplExtent aeObjs;

		m_api->m_data.GetAttr(process, a_proc_of_tmpl, proc_tmpl);
		if(proc_tmpl)
			m_api->m_data.GetAttr(proc_tmpl, a_action_id, sTmplId);

		if(sTmplId==APL_T("ПВБД") || sTmplId==APL_T("ВДЗЦ") || sTmplId==APL_T("ПВОГК") || sTmplId==APL_T("СУД") )
		{
			m_api->m_data.GetAttr(process, a_proc_wo, wobj);
			for(i= 0; i<wobj.GetSize(); i++)
			{
				m_api->m_data.GetAttr(wobj[i], a_wo_object, change);
				aeObjs.Add(change);
			}
			m_api->LoadExtentInfo(aeObjs);
			for(i= 0; i<wobj.GetSize(); i++)
			{
				m_api->m_data.GetAttr(wobj[i], a_wo_object, change);
				if(change && m_api->m_data.IsKindOf(change, m_api->m_change_mgr.e_chng))
				{
					m_api->m_data.GetAttr(change, m_api->m_change_mgr.a_chng_state, sState);
					if(sState==_T("approving"))
						m_api->m_data.PutAttr(change, m_api->m_change_mgr.a_chng_state, _T("not_applied"));
				}
				else
				if (change && m_api->m_data.IsKindOf(change, m_api->m_prd_mgr.e_pdf))
				{
					m_api->m_data.GetAttr(change, m_api->m_prd_mgr.a_apl_pdf_state, sState);
					if(sState==_T("approving"))
						m_api->m_data.PutAttr(change, m_api->m_prd_mgr.a_apl_pdf_state, _T("not_applied"));
				}
			}			
		}
	}

	if(m_AutoSave)m_api->SaveChanges();
	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::EndWfProcess(CaplInstance* process)
{
	bool bRes= true;
	if(!m_data || !m_data->IsConnected()) return false;
	if(process==NULL) return false;
	if(process->GetId()==0) return false;
	if(process->GetType()==0) return false;
	if(e_proc==NULL) return false;
	
	aplExtent ext;
	GetProcessTasks(process, ext);
	
	bool bEnd= true; 
	CString buf;
	CaplInstance* inst= NULL;

	for(int i= 0; i<ext.GetSize(); i++)
	{
		m_data->GetAttr(ext[i], a_task_state, buf);
		if(buf==_T("complete") || buf==_T("cancel") || buf==_T("suspend") ) continue;
		if(IsItemLogicalElement(ext[i])) continue;
		bEnd= false;
	}

	if(bEnd)
	{
		COleDateTime odt;
		int iVal;

		m_api->m_data.NET_GetServerDateTime(odt);
		aplDate2String(odt, buf);	
		m_data->PutAttr(process, a_act_inst_end_date, buf);
		m_api->m_options_mgr.GetOptionValueBN(APL_NO_T("Настройка Workflow\\Автоматически сдавать завершенные процессы в архив"), iVal, 0);
		if(iVal!=0)
			m_data->PutAttr(process, a_proc_archive_date, buf);
		
		double dbl= 100;			
		m_data->PutAttr(process, a_act_inst_percent, dbl);
		
		m_data->PutAttr(process, a_proc_state, _T("completed"));

		if(m_AutoSave)m_api->SaveChanges();	

		CaplInstance* curPerson= m_api->m_appr_mgr.GetCurrentPerson();

		if(true)
		{
			CString sID, sName, sSubject, sContent;
			CaplInstance *owner= NULL, *mgr= NULL;

			m_api->m_data.GetAttr(process, a_action_id, sID);
			m_api->m_data.GetAttr(process, a_action_name, sName);
			
			m_api->m_data.GetAttr(process, a_proc_owner, owner);
			m_api->m_data.GetAttr(process, a_proc_manager, mgr);
			
			sSubject.Format(APL_T("Уведомление о завершении процесса%s\":\"%s"), sID, sName);
			sContent.Format(APL_T("Процесс \"%s\":\"%s\" завершен."), sID, sName);

			aplExtent ext;
			ext.Add(process);

			if(CheckPersonNotify(m_api,owner,_T("#CompleteProcessNotify"))) m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), owner, sSubject, sContent, ext,1,_T("sendet"),false,true);
			if(CheckPersonNotify(m_api,mgr,  _T("#CompleteProcessNotify")) 
				&& owner!=mgr) m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), mgr, sSubject, sContent, ext,1,_T("sendet"),false,true);
		}
		if(m_bCompleteProcessNotify_4_ParentProcess)
		{
			CString sSubject, sContent;
			CString sID_t, sName_t,sID_p,sName_p;

			m_api->m_data.GetAttr(process, a_action_id, sID_p);
			m_api->m_data.GetAttr(process, a_action_name, sName_p);

			aplExtent ext_par_task;
			GetParentTasks(process, ext_par_task);
			LoadTaskInfo(ext_par_task);
			int i;
			for(i=0;i<ext_par_task.GetSize();i++)
			{
				CaplInstance *task_i=ext_par_task[i];
				CaplInstance *performer;
				aplExtent ext;

				m_api->m_data.GetAttr(task_i, a_task_performer, performer);
				m_api->m_data.GetAttr(task_i, a_action_id, sID_t);
				m_api->m_data.GetAttr(task_i, a_action_name, sName_t);

				sSubject.Format(APL_T("Уведомление о завершении процесса  %s:%s"), sID_p, sName_p);
				sContent.Format(APL_T("Завершен процесс  \"%s\":\"%s\"   выполняемый в рамках задания   \"%s\":\"%s\"."), sID_p, sName_p, sID_t, sName_t);

				ext.Add(task_i);

				 if(0!=performer && performer!=curPerson)
				 {
					 m_api->m_message_mgr.CreateMessage((CaplInstance*)(-1), performer, sSubject, sContent, ext,1,_T("sendet"),false,true);
				 }
			}
		}

		if(m_AutoSave)m_api->SaveChanges();	
	}
	else
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Одно или несколько заданий процесса еще не завершены.\nПроцесс нельзя завершить."), MB_OK|MB_ICONERROR);
	}

	return bRes;
}
//*******************************************************************************
CaplInstance* CaplWorkFlowManager::RestartWfProcess(CaplInstance* process)
{
	CaplInstance* newProc= NULL;
	if(!m_data || !m_data->IsConnected()) return NULL;
	if(process==NULL) return NULL;
	if(process->GetId()==0) return NULL;
	if(process->GetType()==0) return NULL;
	if(e_proc==NULL) return NULL;
	
	CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();
	if(!user) return NULL;
	CaplInstance *inst= NULL;
	int iVal;
	
	CaplInstance* owner= NULL, *manager= NULL;
	m_data->GetAttr(process, a_proc_owner, owner);
	m_data->GetAttr(process, a_proc_manager, manager);
	if(manager && m_api->m_data.IsKindOf(manager, m_api->m_appr_mgr.e_official))
		m_api->m_data.GetAttr(manager, m_api->m_appr_mgr.a_official_act_person, manager);
	if(owner!=user)
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(APL_T("Вы не можете перезапустить данный процесс."), MB_OK|MB_ICONERROR);
		return NULL;
	}

	//TerminateWfProcess(process);
	
	CString id, name, dscr, prior;
	CString st_d, fn_d, ch_d;
	aplExtent proc_wo, proc_prot;
	CaplInstance* proc_tmpl= NULL;
	aplExtent aggr;
	CStringArray log;

	m_data->GetAttr(process, a_proc_of_tmpl, proc_tmpl);

//	m_data->GetAttr(process, a_action_id, id);
	m_data->GetAttr(process, a_action_name, name);
	m_data->GetAttr(process, a_action_dscr, dscr);
	
	m_data->GetAttr(process, a_act_inst_prior, prior);

	COleDateTime odt;
	m_api->m_data.NET_GetServerDateTime(odt);
	
	//COleDateTimeSpan odts;
	aplDate2String(odt, st_d);
	double rDuration=0;
	if(proc_tmpl)
		m_data->GetAttr(proc_tmpl, a_proc_tmpl_duration, rDuration);
	
	/*odts.m_span= rDuration;
	odts.SetStatus(COleDateTimeSpan::valid);
	odt+=odts;
	aplDate2String(odt, fn_d);
	odt-=odts;
	odts.m_span= rDuration*2/3;
	odt+=odts;
	aplDate2String(odt, ch_d);*/

	// ЯАИ 10.10.2011:  замена предыдущего
	m_api->m_appr_mgr.LoadHolydaysInCash();
	COleDateTime odt_check,odt_finish;
	FillWfDates(odt,rDuration,odt_check,odt_finish);
	aplDate2String(odt_finish, fn_d);
	aplDate2String(odt_check, ch_d);

//	m_data->GetAttr(process, a_proc_wo, aggr);
//	for(int i= 0; i<aggr.GetSize(); i++)
//	{
//		inst= aggr[i]; 
//		if(inst)
//		{
//			CaplValue val;
//			CaplInstance* wo= NULL;
//			wo= m_data->CreateInstance(e_wo);
//			if(wo)
//			{
//				m_data->GetAttr(inst, a_wo_object, val);
//				m_data->PutAttr(wo, a_wo_object, val);
//				proc_wo.Add(wo);
//			}
//		}
// 	}

	CaplValue val;
	CaplInstance* prot= NULL;
	CaplInstance* wo= NULL;
	int i;
	
	m_data->GetAttr(process, a_proc_task_prot, aggr);
	for(i= 0; i<aggr.GetSize(); i++)
	{
		inst= aggr[i]; 
		if(!inst) continue;
		if(!inst->GetType()) continue;
		
		prot= m_data->CreateInstance(e_task_tmpl);
		if(prot)
		{

			for(int j= 0; j<e_task_tmpl->all_attrs.GetSize(); j++)
			{
				m_data->GetAttr(inst, e_task_tmpl->all_attrs[j], val);
				m_data->PutAttr(prot, e_task_tmpl->all_attrs[j], val);
			}
			proc_prot.Add(prot);
		}
	}

	m_data->GetAttr(process, a_proc_wo, aggr);
	for(i= 0; i<aggr.GetSize(); i++)
	{
		if(!aggr[i]) continue;
		if(!aggr[i]->GetType()) continue;
		if(!m_api->m_data.IsKindOf(aggr[i], e_wo)) continue;
		
		wo= m_api->m_data.CreateInstance(e_wo);
		if(wo)
		{
			for(int j= 0; j<e_wo->all_attrs.GetSize(); j++)
			{
				m_data->GetAttr(aggr[i], e_wo->all_attrs[j], val);
				m_data->PutAttr(wo, e_wo->all_attrs[j], val);
			}
			
			m_api->m_data.PutAttr(wo, a_wo_action, (CaplInstance*)NULL);
			proc_wo.Add(wo);
		}
	}
	
	bool bOldAoutoSave= m_AutoSave;
	m_AutoSave= false;

	newProc= CreateWfProcess(id, name, dscr, proc_tmpl, owner, manager,
		st_d, fn_d, ch_d, proc_prot, proc_wo, prior);

	if(newProc)
	{
		m_data->GetAttr(newProc, a_action_id, id);
		if(id==APL_T("<Автономер>"))
		{
			GenerateProcId(proc_tmpl,id);
			m_data->PutAttr(newProc, a_action_id, id);
		}

		m_data->GetAttr(process, a_proc_first_activity, inst);
		m_data->PutAttr(newProc, a_proc_first_activity, inst);
			
		CaplAttrValue val[3];
		aplExtent ext;
		CaplAggr aggr;
		
		val[0].value.Set(process);
		val[0].attr= a_task_sub_proc;
		m_data->NET_FindInstancesWithAttrValues(e_task, 1, &val[0], ext, false);
		
		if(ext.GetSize()>0)
		{
			LoadTaskInfo(ext[0]);
			m_data->GetAttr(ext[0], a_task_sub_proc, aggr);
			aggr.Add(newProc);
			m_data->PutAttr(ext[0], a_task_sub_proc, aggr);
		}
		
		TerminateWfProcess(process, false);
		RunWfProcess(newProc);		
		
		m_api->m_options_mgr.GetOptionValueBN(APL_NO_T("Настройка Workflow\\Удалять процесс при перезапуске"), iVal, 0);
		if(0!=iVal)
			DeleteWfProcess(process, log, false, false);
	}

	m_AutoSave= bOldAoutoSave;
	if(m_AutoSave)m_api->SaveChanges();

	return newProc;	
}
//*******************************************************************************
bool CaplWorkFlowManager::GetUserProcessTempList(CaplInstance* owner, aplExtent& proc_tmpls)
{
	proc_tmpls.Clear();

	if(!m_data || !m_data->IsConnected()) return false;
//	if(owner==NULL) return false;
//	if(owner->id==0) return false;
//	if(owner->type==0) return false;
	if(e_proc_tmpl==NULL) return false;
	if(e_proc_tmpl->id== 0) return false;
	
	int i, j;
	CaplInstance* inst;

	bool bAdd;
	bool bSystem;
	CString buf;

	aplExtent ext;
	m_data->GetEntityExtent(e_proc_tmpl, ext);
	if(ext.GetSize()<1) return true;

	aplExtent ext_owner_wg;
	m_api->m_appr_mgr.GetAllActualPersOrgs(owner,ext_owner_wg);

	for(i= 0; i<ext.GetSize(); i++)
	{
		m_data->GetAttr(ext[i], a_proc_tmpl_is_system, bSystem);
		if(bSystem) continue;

		if(!owner)
		{
			proc_tmpls.Add(ext[i]);
			continue;
		}

		m_data->GetAttr(ext[i], a_proc_tmpl_state, buf);
		if(buf!=_T("valid")) continue;

		aplExtent holders, managers;
		m_data->GetAttr(ext[i], a_proc_tmpl_holders, holders);
		// Убрано по просьбе ЦКБА 08.04.2022
		//m_data->GetAttr(ext[i], a_proc_tmpl_managers, managers);
		//holders.Append(managers);
		
		bAdd= false;

		for(j= 0; j<holders.GetSize(); j++)
		{	
			CaplInstance *holders_j=holders[j];
			if(m_data->IsKindOf(holders_j, m_api->m_appr_mgr.e_person))
			{
				if(holders_j==owner)
				{
					bAdd= true; break;
				}
			}
			else if(m_data->IsKindOf(holders_j,  m_api->m_appr_mgr.e_org))
			{
				if(aplQFindInstInExtent(ext_owner_wg,holders_j,false)>=0) 
				{
					bAdd= true; break;
				}
			}
			else if(m_data->IsKindOf(holders_j, m_api->m_appr_mgr.e_official))
			{
				m_api->m_data.GetAttr(holders_j, m_api->m_appr_mgr.a_official_act_person, inst);
				if(inst==owner)
				{
					bAdd= true; break;
				}
			}
		}
		
	
		if(bAdd)
		{
			proc_tmpls.Add(ext[i]);
		}
	}

	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::GetProcessTmplHistory(CaplInstance* owner,
	CaplInstance* proc_tmpl, aplExtent& history)
{
	history.Clear();

	if(!m_data || !m_data->IsConnected()) return false;
	
	if(owner==NULL) return false;
	if(owner->GetId()==0) return false;
	if(owner->GetType()==0) return false;
	
	if(proc_tmpl==NULL) return false;
	if(proc_tmpl->GetId()==0) return false;
	if(proc_tmpl->GetType()==0) return false;

	CaplLoadData ld(m_data,DEF_SOURCE);
	ld.AddQuery(_T('b'), proc_tmpl->GetId(), e_proc, a_proc_of_tmpl, true, true);
	if(!ld.LoadEx())
	{
		if(m_api->m_ModeInteractive)
			if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
				AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
	}
	
	aplExtent ext;
	m_data->GetEntityExtent(e_proc, ext);
	CaplInstance *inst1, *inst2, *inst3;
	for(int i= 0; i<ext.GetSize(); i++)
	{
		inst1= NULL; inst2= NULL;
		m_data->GetAttr(ext[i], a_proc_of_tmpl, inst1);
		m_data->GetAttr(ext[i], a_proc_owner, inst2);
		m_data->GetAttr(ext[i], a_proc_manager, inst3);
		CString buf= _T("");
		if(inst1==proc_tmpl && (inst2==owner||inst3==owner))
		{
			m_data->GetAttr(ext[i], a_proc_state, buf);
			if(buf==_T("completed") || buf==_T("terminated"))
				history.Add(ext[i]);
			buf==_T("");
		}
	}

	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::LoadProcessInfo(CaplInstance* proc)
{
	aplExtent ext;
	ext.Add(proc);
	return LoadProcessInfo(ext);
}

bool CaplWorkFlowManager::LoadProcessInfo(aplExtent& procs)
{
	if(!m_data || !m_data->IsConnected()) return false;
	if(e_proc==NULL) return false;
	if(e_proc_tmpl==NULL) return false;
	if(procs.GetSize()==0) return true;
	
	CaplLoadData ld(m_data,DEF_SOURCE);
	for(int i= 0, count = 0; i<procs.GetSize(); i++, ++count)
	{
		if(procs[i]!=NULL)
		{
			if((procs[i]->GetId()!=0) && (procs[i]->GetType()!=0)) ld.AddQuery(0, procs[i], true);
		}

		if(count >= m_MaxItemsLoad || i == procs.Size - 1)
		{
			if(ld.m_queries.GetSize())
			{
				ld.AddQuery(_T('d'), 0, 0, a_proc_task_prot, true, true);
				ld.AddQuery(_T('d'), 0, 0, a_proc_wo, true, true);

				if(!ld.LoadEx())
				{
					if(m_api->m_ModeInteractive)
						if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
							AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
				}

				ld.ClearQuery();
				count = 0;
			}
		}
	}

	return true;
}

//*******************************************************************************
bool CaplWorkFlowManager::ShowProcessProperties(CaplInstance* process)
{
	bool bRes= false;
	if(!m_data || !m_data->IsConnected()) return false;
	if(process==NULL) return false;
	if(process->GetId()==0) return false;
	if(process->GetType()==0) return false;
	if(e_proc==NULL) return false;
	
	CaplSetResourceHandle setres(module_inst);

	aplExtent ext;

	CProcessDlg dlg;
	dlg.m_api= m_api;
	dlg.m_wf_mgr= this;
	dlg.m_process= process;
	dlg.m_sTitle= APL_T("Свойства процесса");

	int nResult = dlg.DoModal();
	if(IDOK==nResult)
	{
		if(dlg.m_lAction==1) RunWfProcess(process);
		else if(dlg.m_lAction==2) SuspendWfProcess(process);
		else if(dlg.m_lAction==4) EndWfProcess(process);
		else if(dlg.m_lAction==8) TerminateWfProcess(process);
	}

	return nResult==IDOK?true:false;
}
//*******************************************************************************
bool CaplWorkFlowManager::GetUserProcessList(CaplInstance* owner, aplExtent& procs, bool bReturnWithArchiveProc, bool bOnlyActiveProc)
{
	procs.Clear();

	if(m_data==NULL) return false;
	if(owner==NULL) return false;
	if(owner->GetId()==0) return false;
	if(owner->GetType()==0) return false;
	if(e_proc==NULL) return false;

	if(m_data->IsConnected())
	{
		CString sQueryTmpl= _T("SELECT Ext_1 OR Ext_2 ")
			_T("FROM ")
			_T("Ext_0{apl_official.actual_person= #%i} ")
			_T("Ext_1{apl_process((.owner= #%i OR .manager= #%i) %s)} ")
			_T("Ext_2{apl_process((.owner IN #Ext_0 OR .manager IN #Ext_0) %s)} ")
			_T("END_SELECT");
		CString sQuery;
		CString sArjJper;
		
		if(!bReturnWithArchiveProc) sArjJper= _T("AND .archive_date = ''");
		if(bOnlyActiveProc) sArjJper= _T(" AND .state != 'completed' AND .state != 'terminated' AND .finish_date > '20100101000000'");

		sQuery.Format(sQueryTmpl, owner->GetId(), owner->GetId(), owner->GetId(), sArjJper, sArjJper);
		
		if(m_api->m_data.NET_QueryEditParse(sQuery))
			m_api->m_data.NET_QueryExecute(procs);

		LoadProcessInfo(procs);
		return true;

		CaplLoadData ld(m_data,DEF_SOURCE);
		int ind1= ld.AddQuery(_T('b'), owner->GetId(), e_proc, a_proc_owner, true, true);		
			ld.AddQuery(_T('d'), ind1, 0, a_proc_task_prot, true, true);
			ld.AddQuery(_T('d'), ind1, 0, a_proc_wo, true, true);
		int ind2= ld.AddQuery(_T('b'), owner->GetId(), e_proc, a_proc_manager, true, true);		
			ld.AddQuery(_T('d'), ind2, 0, a_proc_task_prot, true, true);
			ld.AddQuery(_T('d'), ind2, 0, a_proc_wo, true, true);
		if(!ld.LoadEx())
		{
			if(m_api->m_ModeInteractive)
				if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
					AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
		}
		
		aplExtent ext;
		m_data->GetEntityExtent(e_proc, ext);
	
		CString buf= _T("");
		CaplInstance* inst1, *inst2;
		CaplInstance* proc_tmpl;
		bool bIsSysteml;

		for(int i= 0; i<ext.GetSize(); i++)
		{
			m_api->m_data.GetAttr(ext[i], a_proc_of_tmpl, proc_tmpl);
			if(!proc_tmpl) continue;
			m_api->m_data.GetAttr(proc_tmpl, a_proc_tmpl_is_system, bIsSysteml);
			if(bIsSysteml) continue;

			buf= _T("");
			m_data->GetAttr(ext[i], a_proc_owner, inst1);
			m_data->GetAttr(ext[i], a_proc_manager, inst2);
			
			if(inst2 && m_api->m_data.IsKindOf(inst2, m_api->m_appr_mgr.e_official))
				m_api->m_data.GetAttr(inst2, m_api->m_appr_mgr.a_official_act_person, inst2);
			
			if(!bReturnWithArchiveProc)	m_data->GetAttr(ext[i], a_proc_archive_date, buf);//сдан ли в архив

			if(buf.IsEmpty() && (owner==inst1 || owner==inst2))
				procs.Add(ext[i]);
			
			buf= _T("");
		}
	}

	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::GetProcessTasks(CaplInstance* proc, aplExtent& tasks)
{
	tasks.Clear();

	if(m_data==NULL) return false;
	if(proc==NULL) return false;
	if(proc->GetId()==0) return false;
	if(proc->GetType()==0) return false;
	if(e_task==0) return false;

	if(m_data->IsConnected())
	{
		CaplLoadData ld(m_data,DEF_SOURCE);
		ld.AddQuery(_T('b'), proc->GetId(), e_task, a_task_proc, true, true);

		if(!ld.LoadEx())
		{
			if(m_api->m_ModeInteractive)
				if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
					AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
		}
		
		aplExtent ext;
		m_data->GetEntityExtent(e_task, ext);
		CaplInstance* inst= NULL;
		for(int i= 0; i<ext.GetSize(); i++)
		{
			m_data->GetAttr(ext[i], a_task_proc, inst);
			if(inst==proc)
				tasks.Add(ext[i]);
		}
	}

	return true;
}

bool CaplWorkFlowManager::GetParentTasks(CaplInstance *item, aplExtent& paent_tasks)
{
	paent_tasks.Clear();
	if(0==item) return false;
	if(item->IsDeleted()) return false;

	CaplInstance *process=item;
	if(m_api->m_data.IsKindOf(process,e_task))
		m_api->m_data.GetAttr(process,a_task_proc,process);

	if(0==process) return false;

	CaplLoadData ld(m_data,DEF_SOURCE);
	CaplAttrValue val[2];
	val[0].value.Set(process);
	val[0].attr= a_task_sub_proc;
	m_data->NET_FindInstancesWithAttrValues(e_task, 1, &val[0], paent_tasks, false);

	return true;
}

bool CaplWorkFlowManager::GetProcessTasks(aplExtent& extProcs, aplExtent& tasks)
{
	if (extProcs.GetSize() == 0) return false;

	tasks.Clear();

	CSortClass::SortExtentByInst(extProcs);

	CaplLoadData ld(m_data,DEF_SOURCE);
	for (int i = 0; i < extProcs.GetSize(); ++i)
	{
		ld.AddQuery(_T('b'), extProcs[i]->GetId(), e_task, a_task_proc, true, true);
	}

	if (!ld.LoadEx())
	{
		if(m_api->m_ModeInteractive)
			if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
				AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
	}

	aplExtent ext;
	m_data->GetEntityExtent(e_task, ext);
	CaplInstance* inst= NULL;
	for(int i= 0; i < ext.GetSize(); i++)
	{
		m_data->GetAttr(ext[i], a_task_proc, inst);

		if (aplQFindInstInExtent(extProcs, inst, true) > -1)
			tasks.Add(ext[i]);
	}

	return true;
}

bool CaplWorkFlowManager::CanAddInstanceInProcess(CaplInstance* process, CaplInstance* inst)
{
	if(!process) return true;
	if(!inst) return true;
	if(!m_api) return true;
	if(!m_api->m_data.IsConnected()) return true;
	if(!m_api->m_data.IsKindOf(process, e_proc)) return true;

	CString sPath;
	CString sModuleName;
	CString sFuncName;
	CaplInstance* processTmpl;
	m_api->m_data.GetAttr(process, a_proc_of_tmpl, processTmpl);
	if(!processTmpl) return true;

	m_api->m_data.GetAttr(processTmpl, a_proc_tmpl_add_wo_module, sModuleName);
	m_api->m_data.GetAttr(processTmpl, a_proc_tmpl_add_wo_function, sFuncName);

	if(sModuleName.IsEmpty() || sFuncName.IsEmpty()) return true;

	CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
	if(0!=app)
	{
		sPath= app->m_pszHelpFilePath;
		int iIndex= sPath.ReverseFind(_T('\\'));
		if(-1!=iIndex)
		{
			sPath= sPath.Left(iIndex+1);
		}
	}

	if(sPath.IsEmpty()) return true;
	sPath+=sModuleName;

	bool bRes= true;
	HMODULE hModule = AfxLoadLibrary(sPath);
	if(hModule)
	{
		bool (*pProc) (CaplAPI*, CaplWorkFlowManager*, CaplInstance*, CaplInstance*);
		pProc= NULL;
		(FARPROC&)pProc = GetProcAddress(hModule, (LPCSTR)CaplStringAdapter(sFuncName));

		if(pProc)
			bRes= pProc(m_api, this, process, inst);

		AfxFreeLibrary(hModule);
	}

	return bRes;	
}

bool CaplWorkFlowManager::GetWorkObjects(CaplInstance* task_or_process, aplExtent&objects)
{
	objects.Clear();

	if(!m_api) return false;
	if(!m_api->m_data.IsConnected()) return false;
	if(!task_or_process) return false;

	CaplInstance* process= NULL;
	if(m_api->m_data.IsKindOf(task_or_process, e_task))
		m_api->m_data.GetAttr(task_or_process, a_task_proc, process);
	else if(m_api->m_data.IsKindOf(task_or_process, e_proc))
		process= task_or_process;
	if(!process) return false;

	aplExtent ext;
	CaplInstance* inst;
	int i;

	m_api->m_data.GetAttr(process, a_proc_wo, ext);
	
	m_api->LoadExtentInfo(ext);

	for(i= 0; i<ext.GetSize(); i++)
	{
		m_api->m_data.GetAttr(ext[i], a_wo_object, inst);
		if(inst)
			objects.Add(inst);
	}
	
	m_api->LoadExtentInfo(objects);

	return true;
}

bool CaplWorkFlowManager::CanChangeWorkObjectsList(CaplInstance* process)
{
	if(0==process) return false;
	if(0==process->GetType()) return false;
	//AfxMessageBox(APL_T("Проверка!"));
	int LimitWOExecutor=0;
	m_api->m_options_mgr.GetOptionValueBN( APL_NO_T("Настройка Workflow\\Ограничить возможность  изменения списка рабочих объектов процесса только исполнителем текущего задания"),LimitWOExecutor,0);

	if(0==LimitWOExecutor) return true;

	aplExtent ext_tasks;
	GetProcessTasks(process,ext_tasks);
	if(0==ext_tasks.GetSize()) return true;
	int i;
	CString sState;
	CaplInstance *performer,*cur_pers;
	cur_pers=m_api->m_appr_mgr.GetCurrentPerson();
	if(0==cur_pers) return false; 

	for(i=0;i<ext_tasks.GetSize();i++)
	{
		CaplInstance *task=ext_tasks[i];
		m_api->m_data.GetAttr(task,a_task_state,sState);
		if(sState!=_T("work")) continue;

		m_api->m_data.GetAttr(task,a_task_performer,performer);
		if(performer!=cur_pers)continue;

		return true;
	}

	if(m_api->m_ModeInteractive)
		AfxMessageBox(APL_T("Согласно настройкам, изменять список рабочих объектов может только исполнитель активного задания!"),MB_OK);
	return false;


	return true;
}

//*******************************************************************************
bool CaplWorkFlowManager::FillWfDates(COleDateTime &startDate, double duration, 
									  COleDateTime &checkDate, COleDateTime &finishDate)
{
/*	
	1, 2, 8 января
	23 февраля
	5, 8 марта
	1, 9 мая
	12 июня
	11 октября
	7 ноября
	12, 17, 24 декабря
*/
	/*finishDate = checkDate = startDate;
	COleDateTimeSpan odts;
	odts.SetStatus(COleDateTimeSpan::valid);
	odts.m_span = duration;
	finishDate += odts;
	odts.m_span = duration * 2 / 3;
	checkDate += odts;*/

	// ЯАИ 10.10.2011:  замена предыдущего
	m_api->m_appr_mgr.AddWorkdayToDate(startDate,duration,finishDate);
	m_api->m_appr_mgr.AddWorkdayToDate(startDate,duration*2/3,checkDate);
	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::ShowTmplProperties(CaplInstance *tmpl_or_act)
{
	if(m_data==NULL) return false;
	if(tmpl_or_act==NULL) return false;
	if(tmpl_or_act->GetId()==0) return false;
	if(tmpl_or_act->GetType()==0) return false;

	CaplSetResourceHandle setres(module_inst);
	
	CTmplDialog dlg;
	dlg.m_api= m_api;
	dlg.m_instance= tmpl_or_act;
	dlg.m_wfMgr= this;

	if(IDOK==dlg.DoModal())
	{
		
	}
	return true;
}
//*******************************************************************************
CaplInstance* CaplWorkFlowManager::GetProcessTmplById(LPCTSTR id)
{
	if(!m_data) return 0;
	if(!m_api || !m_api->m_data.IsConnected()) return 0;

	if (id==0)return NULL;
	if(e_proc_tmpl==0) return NULL;

	aplExtent ext;
	CaplAttrValue serch_value;

	serch_value.value.Set(id);
	serch_value.attr=a_action_id;
	m_data->NET_FindInstancesWithAttrValues(e_proc_tmpl, 1, &serch_value, ext, false);
	if(ext.Size==0) return 0;
	
	if(m_data->IsKindOf(ext[0], e_proc_tmpl))
		return ext[0];
	
	return NULL;
}
//*******************************************************************************
bool CaplWorkFlowManager::DeleteWfProcess(CaplInstance *process, CStringArray &procLog, 
										  bool bSave, bool bVerify)
{
	bool bRes= false;
	
	if(!m_data || !m_data->IsConnected()) return false;
	if(process==NULL) return false;
	if(process->GetId()==0) return false;
	if(process->GetType()==0) return true;
	if(e_proc==NULL) return false;
	if(e_task_tmpl==NULL) return false;
	if(e_task==NULL) return false;
	if(e_wo==NULL) return false;
	int i;


	if(!LoadProcessInfo(process)) return false;

	//if(process->GetAccessmode()>aplOWN) {AfxMessageBox(S::NoAccessRight_rus,MB_OK|MB_ICONSTOP); return false;}
	
	CaplInstance *inst= NULL;
	if(bVerify)
	{
		CaplInstance *user= m_api->m_appr_mgr.GetCurrentPerson();			
		CaplInstance* owner= NULL;
		CaplInstance* manager= NULL;
		m_data->GetAttr(process, a_proc_owner, owner);
		m_data->GetAttr(process, a_proc_manager, manager);
		
		if(owner!=user && manager!=user )
		{
			if(m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Вы не можете удалить процесс."), MB_OK|MB_ICONERROR);
			return false;
		}
		else
		{
			//Кто-то свой
			if(owner!=user && m_api->m_ModeInteractive)
			{
				if(IDNO==AfxMessageBox(APL_T("Процесс запущен не Вами, Вы - координатор процесса.\nУдалить процесс?"), MB_YESNO|MB_ICONWARNING|MB_DEFBUTTON2))
					return false;
			}
		}
	}

	CaplAttrValue val[3];
	aplExtent ext;
	
	val[0].value.Set(process);
	val[0].attr= a_task_sub_proc;
	m_data->NET_FindInstancesWithAttrValues(e_task, 1, &val[0], ext, false);
	
	if(ext.GetSize()>0)
	{
		//это подпроцесс
	}

	CaplAdminModeProvider adminmode(&(m_api->m_data),-1, -1,DEF_SOURCE);
	
	CaplAggr aggr;
	int iSource, iResult;
	srand((unsigned)time(NULL));
	iSource= rand();
	iResult= iSource^0x7d24cf18;
	
	//удалить прототипы
	m_data->GetAttr(process, a_proc_task_prot, aggr);
	for(i= 0; i<aggr.GetSize(); i++)
	{
		inst= NULL;
		aggr.GetByIndex(i, inst);
		if(inst)
		{
			m_data->DeleteInstance(inst, false);
		}
	}
	//удалить рабочие объекты
	m_data->GetAttr(process, a_proc_wo, aggr);
	for(i= 0; i<aggr.GetSize(); i++)
	{
		inst= NULL;
		aggr.GetByIndex(i, inst);
		if(inst)
		{
			m_data->DeleteInstance(inst);
		}
	}
	//удалить задания
	GetProcessTasks(process, ext);
	aplSortWfInstances(this, ext, 0, ext.GetSize()-1);//сортировка по дате создания
	for(i= 0; i<ext.GetSize(); i++)
	{
		m_data->GetAttr(ext[i], a_task_sub_proc, aggr);
		for(int j= 0; j<aggr.GetSize(); j++)
		{
			inst= NULL;
			aggr.GetByIndex(j, inst);
			if(inst)//удаление подпроцесса
			{
//					DeleteWfProcess(inst, procLog, false, false);//не сохранять, не проверять владельца
			}
		}

		m_data->DeleteInstance(ext[i], false);
	}
	//удаление процесса
	m_data->DeleteInstance(process, false);
	
	if(bSave)//если необходимо, сохраняем
	{
		if(m_AutoSave)m_api->SaveChanges();
	}

	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::DeleteProcessTemplate(CaplInstance* tmpl, bool bVerify)
{
	if(!m_data || !m_data->IsConnected()) return false;
	if(tmpl==NULL) return false;
	if(tmpl->GetType()==0) return true;
	if(e_proc==NULL) return false;
	if(e_proc_tmpl==NULL) return false;
	
	if(bVerify)
	{		
		if(tmpl->GetAccessmode()>aplOWN) 
		{
			if(m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Вы не можете удалить шаблон процесса.\n\n(недостаточно прав доступа)"), MB_OK|MB_ICONERROR);
			return false;
		}
	}

	CString buf,id,name;

	CaplInstance *TmplUser = NULL;
	m_api->m_data.GetAttr(tmpl, a_proc_tmpl_editor, TmplUser);
	if(TmplUser != NULL)
	{
		CString sMsg, sName;
		m_api->LoadItemInfo(TmplUser);
		m_api->m_appr_mgr.GetPersonName(TmplUser, sName);
		sMsg.Format(APL_T("Данный процесс редактирует %s . Удаление невозможно!"), sName);
		if(m_api->m_ModeInteractive)
			AfxMessageBox(sMsg, MB_ICONSTOP);
		return false;
	}

	m_api->m_data.GetAttr(tmpl,a_action_id,id);
	m_api->m_data.GetAttr(tmpl,a_action_name,name);

	buf=APL_T("Вы действительно хотите удалить шаблон процесса ?\n\n(");
	buf+=id;
	buf+=_T(" : ");
	buf+=name;
	buf+=_T(")");
		
	if(m_api->m_ModeInteractive && IDYES!=AfxMessageBox(buf,MB_YESNO|MB_ICONSTOP|MB_DEFBUTTON2))return false;
	

	int n1;
	CaplLoadData ld(m_data,DEF_SOURCE);
n1= ld.AddQuery(_T('b'), tmpl->GetId(), e_proc, a_proc_of_tmpl, true);
	ld.AddQuery(_T('d'), n1, 0, a_proc_of_tmpl, true);
	ld.AddQuery(_T('d'), n1, 0, a_proc_state, true);
	ld.LoadEx();

	aplExtent ext, prcs;
	m_data->GetEntityExtent(e_proc, ext);
	CaplInstance* inst;

	int i;
	for(i= 0; i<ext.GetSize(); i++)
	{
		inst= NULL;
		m_data->GetAttr(ext[i], a_proc_of_tmpl, inst);
		if(inst==tmpl)
		{
			buf.Empty();
			m_data->GetAttr(ext[i], a_proc_state, buf);
			if(buf!=_T("terminated") && buf!=_T("completed"))
			{
				if(m_api->m_ModeInteractive)
					AfxMessageBox(APL_T("По шаблону выполняются экземпляры процесса.Шаблон нельзя удалять."), MB_OK|MB_ICONERROR);
				return false;
			}
		}
		else 
		{
			ext.Remove(i);
			i--;
			continue;
		}
	}
	
	CStringArray log;
	//Удаление экземпляров процессов
	for(i= 0; i<ext.GetSize(); i++)
	{
		DeleteWfProcess(ext[i], log, false, false);
	}
	
	//Удаление переходов
	GetProcessConnectors(tmpl, ext);
	for(i= 0; i<ext.GetSize(); i++)
	{
		m_data->DeleteInstance(ext[i]);
	}

	//Удаление действий, точек входа и выхода
	GetProcessComponents(tmpl, ext);
	for(i= 0; i<ext.GetSize(); i++)
	{
		m_data->DeleteInstance(ext[i]);
	}

	m_data->DeleteInstance(tmpl);
	if(m_AutoSave)m_api->SaveChanges();

	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::GetProcessConnectors(CaplInstance* tmpl, 
											   aplExtent& connectors)
{
	connectors.Clear();

	if(!m_data || !m_data->IsConnected()) return false;
	if(tmpl==NULL) return false;
	if(tmpl->GetId()==0) return false;
	if(tmpl->GetType()==0) return true;
	if(e_proc==NULL) return false;
	if(e_proc_tmpl==NULL) return false;

	int n1;
	CaplLoadData ld(m_data,DEF_SOURCE);
n1= ld.AddQuery(_T('b'), tmpl->GetId(), e_act_secuence, a_act_secuence_tmpl, true, true);
//	ld.AddQuery(_T('d'), n1, 0, a_act_secuence_tmpl, true);
	ld.AddQuery(_T('d'), n1, 0, a_act_rel_points, true,true);
	ld.AddQuery(_T('d'), n1, 0, a_act_rel_title_point, true,true);
	ld.AddQuery(_T('d'), n1, 0, a_act_rel_font, true,true);
	ld.LoadEx();

	aplExtent ext0;
	
	m_data->GetEntityExtent(e_act_secuence, ext0);

	
	CaplInstance* inst;
	for(int i= 0; i<ext0.GetSize(); i++)
	{
		inst= NULL;
		m_data->GetAttr(ext0[i], a_act_secuence_tmpl, inst);
		if(inst==tmpl)
		{
			connectors.Add(ext0[i]);	
		}
	}
	return true;
}
//*******************************************************************************
bool CaplWorkFlowManager::LoadTemplates()
{
	if(!m_data) return 0;
	if(!m_api || !m_api->m_data.IsConnected()) return 0;

	CaplLoadData ld(m_data,DEF_SOURCE);
	int i=ld.AddQuery(_T('e'), 0, e_proc_tmpl,0, true,true);
	if(!ld.LoadEx())
	{
		if(apidata.GetLastAplError()!=APL_SOCK_OPERATION_IN_PROGRESS)
		{
			if(m_api->m_ModeInteractive)
				AfxMessageBox(APL_T("Ошибка чтения данных (MGR)"), MB_OK|MB_ICONSTOP);
			return false;
		}
	}
	return true;
}
//*******************************************************************************
int CaplWorkFlowManager::TemplateValidCheck(CaplInstance *templ,int errMode)
{
	if(!m_data) return 0;
	if(!m_api || !m_api->m_data.IsConnected()) return 0;
	if(templ==NULL) return 0;

	aplExtent ext0, connectors, activitys, terminators;
	CaplInstance * inst, * inst1;
	int i,j;

	CString log,str; 
	
	// выбираем действия и терминаторы
	m_data->GetEntityExtent(e_act_tmpl, ext0);

//	CaplAttrValue val;
//	val.attr = a_act_tmpl_proc_tmpl;
//	val.value.Set(templ);
//	m_data->NET_FindInstancesWithAttrValues(e_act_tmpl,1, &val, ext0, false); 

	int start=0, end =0;
	for(i=0; i < ext0.GetSize(); i++)
	{
		m_data->GetAttr(ext0[i],a_act_tmpl_proc_tmpl,inst);
		if(inst == templ)
		{
			if(ext0[i]->GetType() == e_activity)
			{
				activitys.Add(ext0[i]);
			}
			else if(ext0[i]->GetType() == e_start_point)
			{
				start++;
				terminators.Add(ext0[i]);
			}
			else if(ext0[i]->GetType() == e_end_point)
			{
				end++;
				terminators.Add(ext0[i]);
			}
		}
	}

	if(activitys.GetSize()==0)
	{
		log+= APL_T("В шаблоне нет действий.\n");
	}
	
	if(start==0)
	{
		log+= APL_T("Нет точек входа.\n");
	}

	if(end==0)
	{
		log+= APL_T("Нет точек завершения.\n");
	}

	// выбираем 

	m_data->GetEntityExtent(e_act_secuence, ext0);

//	val.attr = a_act_secuence_tmpl;
//	val.value.Set(templ);
//	m_data->NET_FindInstancesWithAttrValues(e_act_secuence,1, &val, connectors, false); 


	for(i=0; i < ext0.GetSize(); i++)
	{
		m_data->GetAttr(ext0[i],a_act_secuence_tmpl,inst);
		if(inst == templ)
		{
			connectors.Add(ext0[i]);
		}
	}

	if(connectors.GetSize()==0)
	{
		log+= APL_T("Не заданы переходы.\n");
	}

	// проверяем точки начала \ завершения
	int flag;

	for(i=0; i < terminators.Size; i++)
	{
		flag =0;

		if(start>0 && terminators[i]->GetType() == e_start_point)
		{
			// стартовая точка

			// проверка на наличие исходящего перехода
			for(j=0; j < connectors.Size; j++)
			{
				m_data->GetAttr(connectors[j], a_act_rel_from, inst);
				if(inst == terminators[i])
				{
					flag++;
					
				}
			}

			if(flag == 0)
			{
				//нет перехода

				log += APL_T("Нет перехода из точки входа.\n");

				
			}
			else if(flag>1)
			{
				// больще одного исх. перехода
				
				log += APL_T("Больше одного перехода из точки входа.\n");

				
			}				 


		}
		else if(end >0 && terminators[i]->GetType() == e_end_point)
		{
			//точка завершения

			// проверка на наличие входящих переходов перехода
			for(j=0; j < connectors.Size; j++)
			{
				m_data->GetAttr(connectors[j], a_act_rel_to, inst);
				if(inst == terminators[i])
				{
					flag++;
					break;
				}
			}

			if(flag ==0)
			{
				//нет перехода

				log += APL_T("Нет перехода  в точку завершения.\n");				
				
			}

		}

	}

	// проверка действий
	int in, out;
	CString name;

	for(i=0; i < activitys.Size; i++)
	{
		in=0;
		out=0;

		m_data->GetAttr(activitys[i], a_action_name, name);

		for(j=0 ; j < connectors.Size; j++)
		{
			m_data->GetAttr(connectors[j], a_act_rel_from, inst);
			m_data->GetAttr(connectors[j], a_act_rel_to, inst1);
			

			if(inst==activitys[i])
			{
				out++;
			}
			if(inst1==activitys[i])
			{
				in++;
			}
		}	

		if(in==0)
		{
			CString sBuf;
			sBuf.Format(APL_T("У действия \"%s\" нет входящих переходов.\n"), name);
			log+= sBuf;			
		}
		if(out==0)
		{
			CString sBuf;
			sBuf.Format(APL_T("У действия \"%s\" нет исходящих переходов.\n"), name);
			log+= sBuf;
		}
	}

	if(errMode==TRUE && log!=_T(""))
	{
		if(m_api->m_ModeInteractive)
			AfxMessageBox(log);
		return false;
	}

	return true;
}
//*******************************************************************************
void CaplWorkFlowManager::AnalyzeWorkTimes(CaplInstance* ciTemplate,CaplInstance* ciActivity)
{
	if(!m_api || !m_api->m_data.IsConnected()) return;
	
	CaplSetResourceHandle setres(module_inst);

	CTaskTimesDialog dlg;
	dlg.m_pApi=m_api;
	dlg.m_ciSelTempl=ciTemplate;
	dlg.m_ciSelAct=ciActivity;
	dlg.m_wf_mgr=this;
	dlg.DoModal();
}
//*******************************************************************************
void CaplWorkFlowManager::StartManyProcs(CaplInstance* ciTemplate,CaplInstance* ciTask, aplExtent *created_proc/*= NULL*/)
{
	if(!m_api || !m_api->m_data.IsConnected()) return;

	aplExtent			aeTaskSubPrc;

	CaplInstance*		ciTempl	=NULL;


	CMProcStartDialog	dlg2;

//	if(NULL==ciTemplate && NULL==ciTask)
//		return;

	
	if(NULL==ciTemplate)
	{
		aplExtent ext; 
		aplExtent subpr;
		CaplInstance* activity;
		
		int iVal;
		m_api->m_options_mgr.GetOptionValueBN(APL_NO_T("Настройка Workflow\\Не давать запускать подпроцессы, не указанные в настройке действия"), iVal, 0);
		if(iVal==1)
		{
			/*Только то, что указано в действии*/
			m_api->m_data.GetAttr(ciTask, a_task_activity, activity);
			m_api->m_data.GetAttr(activity, a_activity_sub_proc_tmpl, ext);

			if(ext.GetSize()==0)
			{
				if(m_api->m_ModeInteractive)
					AfxMessageBox(APL_T("Для задания не заданы шаблоны подпроцессов!"), MB_ICONERROR|MB_OK);
				return;
			}
		}
		else
		{
			GetUserProcessTempList(m_api->m_appr_mgr.GetCurrentPerson(), ext);	
			m_api->m_data.GetAttr(ciTask, a_task_activity, activity);
			m_api->m_data.GetAttr(activity, a_activity_sub_proc_tmpl, subpr);
			ext.Append(subpr);
			if(ext.GetSize()==0)
			{
				if(m_api->m_ModeInteractive)
					AfxMessageBox(APL_T("Вы не являетесь владельцем ни одного процесса!"), MB_ICONERROR|MB_OK);
				return;
			}
		}

//		CaplInstance*user=m_data->GetCurrUser();
//		if(user!=0)
//		GetUserProcessTempList(0,ext);
		
		
		ciTempl=SelectTemplateSchema(ext);
		
		if(ciTempl==0) return;
	}
	else
		ciTempl=ciTemplate;

	dlg2.m_api=m_api;
	dlg2.m_wf_mgr=this;
	dlg2.m_bAutoAddProcInst=true;

	dlg2.m_ciTask=ciTask;
	dlg2.m_ciTemplate=ciTempl;

	CaplSetResourceHandle setres(module_inst);

	if(IDCANCEL==dlg2.DoModal())
	{
		return;
	}
	
	if(created_proc)
	{
		created_proc->Append(dlg2.m_aeProcesses);
	}

	if(NULL!=ciTask)
	{
		CString sParentName,sName;
		CaplInstance *parent_proc;
		m_api->m_data.GetAttr(ciTask,a_task_proc,parent_proc);
		if(0!=parent_proc)
		{
			m_api->m_data.GetAttr(parent_proc,a_action_name,sParentName);
		}

		m_api->m_data.GetAttr(ciTask,a_task_sub_proc,aeTaskSubPrc);

		//aeTaskSubPrc.Append(dlg2.m_aeProcesses);
		int i;
		for(i=0;i<dlg2.m_aeProcesses.GetSize();i++)
		{
			CaplInstance *proc=dlg2.m_aeProcesses[i];
			if(sParentName!=_T(""))
			{
				m_api->m_data.GetAttr(proc,a_action_name,sName);
				sName+=_T(" / ");
				sName+=sParentName;
				m_api->m_data.PutAttr(proc,a_action_name,sName);
			}
			aeTaskSubPrc.Add(proc);
		}
		m_api->m_data.PutAttr(ciTask,a_task_sub_proc,aeTaskSubPrc);

		m_api->m_data.NET_SaveChanges();
	}
}
//***********************************************************************
void CaplWorkFlowManager::ShowTemplateSchema(CaplInstance *wf_template, CaplInstance *task_for_sel)
{
	if(!m_api || !m_api->m_data.IsConnected()) return;

	if(m_api==0) return;
	if(wf_template==0 && task_for_sel==0 ) return;
	if(wf_template==0)
	{
		m_api->m_data.GetAttr(task_for_sel,a_act_tmpl_proc_tmpl,wf_template);
		if(wf_template==0 && task_for_sel!=0)
		{
			LoadActivityInfo(task_for_sel);
			m_api->m_data.GetAttr(task_for_sel,a_act_tmpl_proc_tmpl,wf_template);
		}
	}
	if(wf_template==0) return;
	if(wf_template->GetType()==0) return;

	CaplSetResourceHandle setres(module_inst);

	CViewWfTemplateDlg dlg;

	dlg.m_wf_mgr=this;
	dlg.m_template=wf_template;
	dlg.m_task_for_sel=task_for_sel;

	dlg.DoModal();
}
//***********************************************************************
CaplInstance  *CaplWorkFlowManager::SelectTemplateSchema(aplExtent &templates, CaplInstance *sel_template, bool bShowAllTemplates, long SelectMode)
{
	if(!m_api || !m_api->m_data.IsConnected()) return NULL;

	if(m_api==0) return 0;
	//if(wf_template==0 && task_for_sel==0 ) return;


	CSelectProcessTemplDlg dlg;

	dlg.m_api=m_api;
	dlg.m_wf_mgr=this;
	dlg.m_templates.Append(templates);
	dlg.m_sel_template=sel_template;
	dlg.m_bShowAllTemplates = bShowAllTemplates;
	dlg.m_SelectMode = SelectMode;

	if(IDOK==dlg.DoModal()) return dlg.m_sel_template;


	return 0;
}
//******************************************************
CaplInstance *CaplWorkFlowManager::SelectTemplateSchemaInEditor(aplExtent &templates, int  &iEditorResultMode)
{
	if(!m_api || !m_api->m_data.IsConnected()) return NULL;

	iEditorResultMode=0;
	if(m_api==0) return 0;
	//if(wf_template==0 && task_for_sel==0 ) return;

	CSelectProcessTemplDlg dlg;

	dlg.m_api=m_api;
	dlg.m_wf_mgr=this;
	dlg.m_templates.Append(templates);
	dlg.m_bEditorMode=true;

	if(IDOK==dlg.DoModal())
	{
		iEditorResultMode=dlg.m_iEditorResultMode;
		return dlg.m_sel_template;
	}

	return 0;
}

BOOL CaplWorkFlowManager::RunProgrammModule(CaplInstance* task, aplExtent& ApprovedWO, CaplInstance* connector, bool bStartModule/* = true */)
{
	if(!m_api || !m_api->m_data.IsConnected()) return FALSE;

	BOOL bRes= TRUE;
	if(!task) return bRes;

	CaplInstance* activity;
	m_api->m_data.GetAttr(task, a_task_activity, activity);
	if(!activity) return bRes;

	CString sPath;
	CString sModuleName;
	CString sFuncName;

	if(bStartModule)
	{
		m_api->m_data.GetAttr(activity, a_activity_ed_st_mod, sModuleName);
		m_api->m_data.GetAttr(activity, a_activity_ed_st_fun, sFuncName);
	}
	else
	{
		m_api->m_data.GetAttr(activity, a_activity_ed_fn_mod, sModuleName);
		m_api->m_data.GetAttr(activity, a_activity_ed_fn_fun, sFuncName);		
	}

	if(sModuleName.IsEmpty() || sFuncName.IsEmpty()) return TRUE;

	CWinApp *app=AfxGetApp(); // При вызове из ActiveX возвращает 0
	if(0!=app)
	{
		sPath= app->m_pszHelpFilePath;
		int iIndex= sPath.ReverseFind(_T('\\'));
		if(-1!=iIndex)
		{
			sPath= sPath.Left(iIndex+1);
		}
	}
	
	if(sPath.IsEmpty()) return TRUE;
	sPath+=sModuleName;

	// если действие не требует подписи объектов, то просто берем все рабочие объекты
	if(ApprovedWO.Size == 0)
	{
		CaplInstance *activity = 0;
		m_api->m_data.GetAttr(task, a_task_activity, activity);

		if(activity)
		{
			bool notSign;
			m_api->m_data.GetAttr(activity, a_activity_not_sign, notSign);

			if(true == notSign)
			{
				CaplInstance *process = 0;
				m_api->m_data.GetAttr(task, a_task_proc, process);

				if(0 != process)
				{
					m_api->m_data.GetAttr(process, a_proc_wo, ApprovedWO);
				}
			}
		}
	}
	
	HMODULE hModule = AfxLoadLibrary(sPath);
	if(hModule)
	{
		bool (*pProc) (CaplAPI*, CaplWorkFlowManager*, CaplInstance*, aplExtent&, CaplInstance*);
		pProc= NULL;
		(FARPROC&)pProc = GetProcAddress(hModule, (LPCSTR)CaplStringAdapter(sFuncName));
		
		if(pProc)
		{
			bRes= FALSE;
			if(pProc(m_api, this, task, ApprovedWO, connector))
				bRes= TRUE;
		}

		AfxFreeLibrary(hModule);
	}
	
	return bRes;
}

bool CaplWorkFlowManager::GetProcessPrototypes(CaplInstance* proc_or_tmpl, aplExtent& prots)
{
	prots.Clear();
	
	if(!proc_or_tmpl) return false;
	if(!proc_or_tmpl->GetType()) return false;
	if(!m_api) return false;
	if(!m_api->m_data.IsConnected()) return false;

	aplExtent ext;
	CaplInstance* proc_template= NULL;
	CaplInstance* inst;

	if(m_api->m_data.IsKindOf(proc_or_tmpl, e_proc_tmpl))
		proc_template= proc_or_tmpl;
	else if(m_api->m_data.IsKindOf(proc_or_tmpl, e_proc))
		m_api->m_data.GetAttr(proc_or_tmpl, a_proc_of_tmpl, proc_template);

	CaplLoadData ld (&m_api->m_data, DEF_SOURCE);

	int i1= ld.AddQuery(_T('b'), proc_template->GetId(), e_proc_prot, a_proc_prot_tmpl, true, true);
	ld.AddQuery(_T('r'), i1, e_task_tmpl, a_task_tmpl_proc_prot, true, true);
	ld.LoadEx();

	m_api->m_data.GetEntityExtent(e_proc_prot, ext);

	for(int i=0; i<ext.GetSize(); i++)
	{
		m_api->m_data.GetAttr(ext[i], a_proc_prot_tmpl, inst);
		if(inst==proc_template)
			prots.Add(ext[i]);
	}

	return true;
}

bool CaplWorkFlowManager::GetProcessPrototypeItems(CaplInstance* proc_or_tmpl, aplExtent& items)
{
	items.Clear();

	if(!proc_or_tmpl) return false;
	if(!proc_or_tmpl->GetType()) return false;
	if(!m_api) return false;
	if(!m_api->m_data.IsConnected()) return false;

	CaplLoadData ld (&m_api->m_data, DEF_SOURCE);

	int i1= ld.AddQuery(_T('b'), proc_or_tmpl->GetId(), e_task_tmpl, a_task_tmpl_proc_prot, true, true);
	ld.LoadEx();

	aplExtent ext;
	CaplInstance* inst= NULL;

	m_api->m_data.GetEntityExtent(e_task_tmpl, ext);

	for(int i= 0; i<ext.GetSize(); i++)
	{
		m_api->m_data.GetAttr(ext[i], a_task_tmpl_proc_prot, inst);
		if(inst==proc_or_tmpl)
			items.Add(ext[i]);
	}

	return true;
}

CaplInstance* CaplWorkFlowManager::CreateProcessPrototype(CaplInstance* proc_tmpl)
{
	if(!proc_tmpl) return NULL;
	if(!proc_tmpl->GetType()) return NULL;
	if(!m_api) return NULL;
	if(!m_api->m_data.IsConnected()) return NULL;
	
	CaplSetResourceHandle setres(module_inst);

	CListDialog listDlg;
	aplExtent prot_items;
	
	CaplInstance* prototype= m_api->m_data.CreateInstance(e_proc_prot);
	if(!prototype) return NULL;
	m_api->m_data.PutAttr(prototype, a_proc_prot_tmpl, proc_tmpl);

	listDlg.m_wf_mgr= this;
	listDlg.m_api= m_api;

	listDlg.m_sItemsType= _T("task_prototype");
	listDlg.m_sTitle= APL_T("Прототипы заданий");
	listDlg.m_proc_tmpl= proc_tmpl;
	listDlg.m_process= NULL;
	listDlg.m_prototype= prototype;
	listDlg.m_items= &prot_items;
	listDlg.m_bReadOnly= false;

	if(IDOK!=listDlg.DoModal())
	{
		m_api->m_data.DeleteInstance(prototype);
		prototype= NULL;
	}
	return prototype;	
}

bool CaplWorkFlowManager::ShowPrototypes(CaplInstance* proc_or_prot, aplExtent* existProts, bool bReadOnly/* = false */)
{
//	if(!proc_or_prot) return false;
//	if(!proc_or_prot->GetType()) return false;
	if(!m_api) return false;
	if(!m_api->m_data.IsConnected()) return false;
	
	CaplInstance* process= NULL;
	CaplInstance* prototype= NULL;
	CaplInstance* process_tmpl= NULL;
	CaplInstance* inst= NULL;
	aplExtent prot_items;
	
	if(m_api->m_data.IsKindOf(proc_or_prot, e_proc))
	{
		process= proc_or_prot;
		m_api->m_data.GetAttr(process, a_proc_of_tmpl, process_tmpl);
		m_api->m_data.GetAttr(process, a_proc_task_prot, prototype);
	}
	else if(m_api->m_data.IsKindOf(proc_or_prot, e_proc_prot))
	{
		prototype= proc_or_prot;
		m_api->m_data.GetAttr(prototype, a_proc_prot_tmpl, process_tmpl);
		GetProcessPrototypeItems(prototype, prot_items);
	}
	else if(m_api->m_data.IsKindOf(proc_or_prot, e_proc_tmpl))
	{
		process_tmpl= proc_or_prot;
	}
	
	CaplSetResourceHandle setres(module_inst);

	CListDialog listDlg;

	listDlg.m_wf_mgr= this;
	listDlg.m_api= m_api;

	listDlg.m_sItemsType= _T("task_prototype");
	listDlg.m_sTitle= APL_T("Прототипы заданий");
	listDlg.m_proc_tmpl= process_tmpl;
	listDlg.m_process= process;
	listDlg.m_prototype= prototype;
	if(existProts) listDlg.m_items= existProts;
	else listDlg.m_items= &prot_items;
	listDlg.m_bReadOnly= bReadOnly;

	if(IDOK==listDlg.DoModal())
	{
		
	}
	return true;
}

bool CaplWorkFlowManager::FindProcessContained(CaplInstance *ciItem, aplExtent &aeExtOut)
{
	aeExtOut.Clear();
	if(!ciItem) return false;

	CString sSql, t_str;
	
	t_str = _T("SELECT Ext_1 FROM Ext_1 {apl_process.work_objects->apl_work_object.object= #%i} END_SELECT");
	sSql.Format(t_str, ciItem->GetId());

	if(m_api->m_data.NET_QueryEditParse(sSql, false, &t_str) == false) return false;
	m_api->m_data.NET_QueryExecute(aeExtOut);	
	
	if (aeExtOut.GetSize() > 0)
		LoadProcessInfo(aeExtOut);

	return true;
}

bool CaplWorkFlowManager::FindProcessContained(aplExtent& extItems, aplExtent& extOut)
{
	extOut.Clear();
	if (extItems.GetSize() == 0) return false;

	CString sSql, t_str, ext0, buf, buf1;

	for (int i = 0; i < extItems.GetSize(); ++i)
	{
		buf.Format(_T("#%i"), extItems[i]->GetId());
		if (i != extItems.GetSize() - 1)
			buf += _T(",");

		buf1 += buf;
	}

	ext0.Format(_T("Ext_0 {%s}"), buf1);

	t_str = _T("SELECT Ext_1 FROM %s Ext_1 {apl_process.work_objects->apl_work_object.object IN #Ext_0} END_SELECT");
	sSql.Format(t_str, ext0);

	if (m_api->m_data.NET_QueryEditParse(sSql, false, &t_str) == false) return false;
	m_api->m_data.NET_QueryExecute(extOut);	

	if (extOut.GetSize() > 0)
		LoadProcessInfo(extOut);

	return true;
}

bool CaplWorkFlowManager::GetItemColor(CaplInstance *item, COLORREF &color, bool *bWarning)
{
	color=RGB(0,0,0);
	if(0!=bWarning) *bWarning=false;
	if(0==item) return false;
	if(0==item->GetType()) return false;
	if(item->GetAccessmode()>aplRO) return false;
	if(!m_api->m_data.IsKindOf(item,e_act_inst)) return false;

	if(FALSE==m_b_mark_work_with_color && FALSE==m_b_mark_ended_work_with_color) return true;
	
	CString sEndDate,sFinishDate;

	m_api->m_data.GetAttr(item, a_act_inst_finish_date, sFinishDate);	

	if(sFinishDate ==_T("")) return true;	// имеет смысл только если задана  плановая дата завершения

	COleDateTime odt_finish; aplString2Date(sFinishDate,odt_finish);

	m_api->m_data.GetAttr(item, a_act_inst_end_date, sEndDate);

	bool bSetWarning=false;

	static COLORREF color_overdue=RGB(255,0,0);
	static COLORREF color_ends=RGB(255,128,0);
	static COLORREF color_much_time=RGB(0,128,0);
	static COLORREF color_much_time_end=RGB(64,128,640);

	static COLORREF color_end_overdue=aplColor_MixColor(color_overdue,RGB(128,128,128),75);
	static COLORREF color_end_earlier=aplColor_MixColor(color_much_time_end,RGB(128,128,128),75);
	static COLORREF color_end_in_time=RGB(128,128,128);
	
	if(sEndDate!=_T("")) // Процесс завершен
	{
		if(!m_b_mark_work_with_color) return true;
		COleDateTime odt_end; aplString2Date(sEndDate,odt_end);
		COleDateTimeSpan ds=odt_end - odt_finish; // На сколько просрочено
		if(ds.m_span>0) color=color_end_overdue; // Просрочено 
		else if(ds.m_span<(-m_i_mark_work_with_color_warning_time)) color=color_end_earlier;
		else color=color_end_in_time;
	}
	else // Процесс не завершен
	{
		if(!m_b_mark_ended_work_with_color) return true;
		COleDateTimeSpan ds = odt_finish - COleDateTime::GetCurrentTime(); // сколько осталось до завершения

		if(ds.m_span<0) {color=color_overdue; bSetWarning=true;} // Просрочено
		else if(ds.m_span>m_i_mark_work_with_color_warning_time) {color=color_much_time;} // Больше 3 суток на зваершение
		else  {color=color_ends; bSetWarning=true;}
	}
	if(bSetWarning && 0!=bWarning) *bWarning=false;

	return true;
}

void CaplWorkFlowManager::ShowColorLegend()
{
	CaplSetResourceHandle setres(module_inst);
	CWfColorDialog dlg;
	dlg.DoModal();

}


CaplInstance* CaplWorkFlowManager::StopAllAddRunLogcalElement(CaplInstance* task_log_el)
{
	if(0==task_log_el) return 0;
	if(!IsItemLogicalElement(task_log_el)) return 0;

	CaplInstance *process;
	m_data->GetAttr(task_log_el, a_task_proc, process);
	LoadProcessInfo(process);
	StopAllProcessTask(process);
	return EndLogicalTask(task_log_el);
}