/*************************************************************************************************/
/*!
   	@file		main.h
	@author 	Fanzo
 	@date 		2008/5/13
*/
/*************************************************************************************************/
#pragma		once

///////////////////////////////////////////////////////////////////////////////////////////////////
//include files
#include	<windows.h>
#include	<math.h>

using namespace icubic;
using namespace shared;


///////////////////////////////////////////////////////////////////////////////////////////////////
// preprocessor deifne

#define create_item( obj_name , title_obj_name , title , view_height )																								\
	title_obj_name->SetString( title );																																\
	title_obj_name->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( m_es , y ) , isize( p->m_rect.Width() - m_es * 2 , m_ts ) ) );			\
	y += title_obj_name->GetRect().Height();																														\
	obj_name->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( m_es , y ) , isize( p->m_rect.Width() - m_es * 2 , view_height ) ) );		\
	obj_name->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );																						\
	y += obj_name->GetRect().Size().height;

///////////////////////////////////////////////////////////////////////////////////////////////////
// type define

///////////////////////////////////////////////////////////////////////////////////////////////////
// classes define

/**************************************************************************************************
"Control1View" class 
**************************************************************************************************/
class Control1View : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )	
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_map_end( View )

// variable member
public:
	instance<SeparateView>		m_color_t;
	instance<ColorCfgView>		m_color;
	instance<SeparateView>		m_affine_t;
	instance<AffineCfgView>		m_affine;
	instance<SeparateView>		m_anti_t;
	instance<AntiCfgView>		m_anti;
	instance<SeparateView>		m_samplescale_t;
	instance<SampleScaleCfgView>m_samplescale;
	instance<SeparateView>		m_fillrule_t;
	instance<FillruleCfgView>	m_fillrule;
	instance<SeparateView>		m_disp_state_t;
	instance<DispOutlineCfgView>m_disp_state;
	instance<SeparateView>		m_angle_t;
	instance<AngleCfgView>		m_angle;
	instance<SeparateView>		m_width_t;
	instance<WidthCfgView>		m_width;
	instance<SeparateView>		m_blender_t;
	instance<BlenderCfgView>	m_blender;
	instance<SeparateView>		m_processor_t;
	instance<ProcessorCfgView>	m_processor;

private:
	rControlMsg						m_msg;
	int								m_id;
	
	const int						m_es;
	const int						m_ts;
	
// "IControlMsg" msg	
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	iControlMsg	ck = m_msg.lock();
	if( ck == true )
		ck->ValueChanged_controlmsg( m_id );
}
// msg functions
protected:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	int		y = m_es;
	create_item( m_color , m_color_t , L"color" , 65 );
	create_item( m_affine , m_affine_t , L"affine" , 80 );
	create_item( m_anti , m_anti_t , L"antialias" , 40 );
	create_item( m_samplescale , m_samplescale_t , L"samplescale" , 20 );
	create_item( m_fillrule , m_fillrule_t , L"fillrule" , 35 );
	create_item( m_disp_state , m_disp_state_t , L"disp switch" , 45 );
	create_item( m_angle , m_angle_t , L"arc angle" , 20 );
	m_angle->SetValue( PI_R2_f );
	create_item( m_width , m_width_t , L"stroke width" , 20 );
	create_item( m_blender , m_blender_t , L"blender" , 20 );
	create_item( m_processor , m_processor_t , L"processor" , 20 );

	m_color->SetValue( rgba( 127 , 191 , 121 , 255 ) );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	DrawConfigBack( (iSurfaceDest)p->m_surface , GetRect().Size() );
}

// public functions
public:
//=================================================================================================
Control1View() : m_id( 0 ) , m_es( 5 ) , m_ts( 11 )
{
}
//=================================================================================================
void SetMsgCallback
		(
		rControlMsg&		msg , 
		int					id
		)
{
	m_msg	= msg;
	m_id	= id;
}
};

/**************************************************************************************************
"Control2View" class 
**************************************************************************************************/
class Control2View : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )	
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_map_end( View )

// variable member
public:
	instance<SeparateView>		m_start_cap_t;
	instance<CapCfgView>		m_start_cap;
	instance<SeparateView>		m_center_cap_t;
	instance<CapCfgView>		m_center_cap;
	instance<SeparateView>		m_end_cap_t;
	instance<CapCfgView>		m_end_cap;
	instance<SeparateView>		m_loop_t;
	instance<LoopCfgView>		m_loop;
	instance<SeparateView>		m_joint_t;
	instance<JointCfgView>		m_joint;
	instance<SeparateView>		m_bridge_t;
	instance<InnerBridgeCfgView>m_bridge;
	instance<SeparateView>		m_edittype_t;
	instance<EdittypeCfgView>	m_edittype;
	instance<SeparateView>		m_gentype_t;
	instance<GenStrokeCfgView>	m_gentype;
	instance<SeparateView>		m_dash_t;
	instance<DashCfgView>		m_dash;

private:
	rControlMsg						m_msg;
	int								m_id;
	
	const int						m_es;
	const int						m_ts;
	
// "IControlMsg" msg	
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	iControlMsg	ck = m_msg.lock();
	if( ck == true )
		ck->ValueChanged_controlmsg( m_id );
}
// msg functions
protected:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	int		y = m_es;
	create_item( m_start_cap , m_start_cap_t , L"start cap" , 30 );
	create_item( m_center_cap , m_center_cap_t , L"dash cap" , 30 );
	create_item( m_end_cap , m_end_cap_t , L"end cap" , 30 );
	create_item( m_loop , m_loop_t , L"loop state" , 30 );
	create_item( m_joint , m_joint_t , L"joint type" , 45 );
	create_item( m_bridge , m_bridge_t , L"bridge type" , 45 );
	create_item( m_gentype , m_gentype_t , L"gen type" , 30 );
	create_item( m_dash , m_dash_t , L"dash interval" , 75 );
	create_item( m_edittype , m_edittype_t , L"path type" , 75 );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	DrawConfigBack( (iSurfaceDest)p->m_surface , GetRect().Size() );
}

// public functions
public:
//=================================================================================================
Control2View() : m_id( 0 ) , m_es( 5 ) , m_ts( 11 )
{
}
//=================================================================================================
void SetMsgCallback
		(
		rControlMsg&		msg , 
		int					id
		)
{
	m_msg	= msg;
	m_id	= id;
}
};
/**************************************************************************************************
"MainView" class 
**************************************************************************************************/
class MainView : public View , public IControlMsg
{
	query_begin()
	iface_hook( IControlMsg , IControlMsg_IID )
	query_end( View )

	msg_view_map_begin()
	msg_view_hook( Create , OnCreate )
	msg_view_hook( Update , OnUpdate )
	msg_view_hook( Size , OnSize )
	msg_view_hook( LDragStart , OnLDragStart )
	msg_view_hook( LDrag , OnLDrag )
	msg_view_hook( LDragEnd , OnLDragEnd )
	msg_view_hook( LDragCancel , OnLDragCancel )
	msg_view_map_end( View )

// variable member
private:
	instance<Control1View>			m_control1;
	instance<Control2View>			m_control2;
	instance<TimeCfgView>			m_time;

	instance<PathSegmentToOutline>	m_path;
	instance<Outline>				m_outline;
	instance<PaintSolidColor>		m_source;
	instance<EdgemapOutline>		m_map;
	instance< RendererOutline >		m_renderer;

	int									m_edit_pnt;
	fvector2							m_pnt[8];

	const int							m_handle_r;
	const rgb							m_bc;
	const rgb							m_hlc;
	const rgb							m_hcc;
	const rgb							m_oc;
	const rgb							m_opc;
	const rgba							m_pc;
	
// msg functions
private:
//=================================================================================================
void cb_call ValueChanged_controlmsg
		(
		int		id
		)
{
	RequireUpdate( irect( ivector2( 0 , 0 ) , GetRect().Size() ) , false );
}
// functions
private:
//=================================================================================================
void DrawHandle
		(
		iSurfaceDest&	surface
		)
{
	isize		size= GetRect().Size();			
	faffine		aff = faffine::GetMove( fvector2( ( float )size.width / 2.0f , ( float )size.height / 2.0f ) ) * m_control1->m_affine->GetValue();

	fvector2	pnt[_countof( m_pnt )];
	int			pntnum	= 0;
	int			i;
	if( m_control2->m_edittype->GetValue() == Multi_Edittype )
	{
		pntnum	= _countof( m_pnt );
		for( i = 0 ; i < _countof( m_pnt ) ; i++ )
			pnt[i] = aff.Transform( m_pnt[i] );
		DrawLine( surface , pnt[1] , pnt[2] , 1.0f , m_hlc );
		DrawLine( surface , pnt[2] , pnt[3] , 1.0f , m_hlc );
		DrawLine( surface , pnt[3] , pnt[4] , 1.0f , m_hlc );
		DrawLine( surface , pnt[4] , pnt[5] , 1.0f , m_hlc );
		DrawLine( surface , pnt[5] , pnt[6] , 1.0f , m_hlc );
	}
	else if( m_control2->m_edittype->GetValue() == Line_Edittype )
	{
		pnt[pntnum] = aff.Transform( m_pnt[0] );
		pntnum++;
		pnt[pntnum] = aff.Transform( m_pnt[1] );
		pntnum++;
	}
	else if( m_control2->m_edittype->GetValue() == Arc_Edittype )
	{
		pnt[pntnum] = aff.Transform( m_pnt[6] );
		pntnum++;
		pnt[pntnum] = aff.Transform( m_pnt[7] );
		pntnum++;
	}
	else if( m_control2->m_edittype->GetValue() == BezierQ_Edittype )
	{
		pnt[pntnum] = aff.Transform( m_pnt[1] );
		pntnum++;
		pnt[pntnum] = aff.Transform( m_pnt[2] );
		pntnum++;
		pnt[pntnum] = aff.Transform( m_pnt[3] );
		pntnum++;
		DrawLine( surface , pnt[0] , pnt[1] , 1.0f , m_hlc );
		DrawLine( surface , pnt[1] , pnt[2] , 1.0f , m_hlc );
	}
	else if( m_control2->m_edittype->GetValue() == BezierC_Edittype )
	{
		pnt[pntnum] = aff.Transform( m_pnt[3] );
		pntnum++;
		pnt[pntnum] = aff.Transform( m_pnt[4] );
		pntnum++;
		pnt[pntnum] = aff.Transform( m_pnt[5] );
		pntnum++;
		pnt[pntnum] = aff.Transform( m_pnt[6] );
		pntnum++;
		DrawLine( surface , pnt[0] , pnt[1] , 1.0f , m_hlc );
		DrawLine( surface , pnt[1] , pnt[2] , 1.0f , m_hlc );
		DrawLine( surface , pnt[2] , pnt[3] , 1.0f , m_hlc );
	}
	for( i = 0 ; i < pntnum ; i++ )
		DrawCircle( surface , pnt[i] , ( float )m_handle_r , m_hcc );
}
// msg functions
private:
//=================================================================================================
void OnCreate
		(
		Create_ViewPM*	p
		)
{
	m_control1->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 1 , 1 ) , isize( 130 , 480 ) ) );
	m_control1->SetMsgCallback( ( rControlMsg )( reference )this_object() , 100 );

	m_time->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( 135 , 0 ) , isize( 300 , 16 ) ) );
	m_time->SetMsgCallback( ( rControlMsg )( reference )this_object() , 0 );

	m_control2->Create( ( rViewParentCtrl )( reference )this_object() , irect( ivector2( p->m_rect.xmax - 130 - 1 , 1 ) , isize( 130 , 505 ) ) );
	m_control2->SetMsgCallback( ( rControlMsg )( reference )this_object() , 100 );
}
//=================================================================================================
void OnUpdate
		(
		Update_ViewPM*	p
		)
{
	ColorBlt( (iSurfaceDest)p->m_surface , p->m_rect , m_bc , Onezero_BltBlendType );	
	m_time->BeginMeasure();
	
	m_outline->Reset();
	int		type = m_control2->m_gentype->GetStrokeType();
	instance<OutlineGenStroke>&	stroke	= m_control2->m_gentype->GetStroke();
	instance<OutlineGenDash>&	dash	= m_control2->m_gentype->GetDash();
	if( type == 0 )
	{
		stroke->SetStrokeWidth( m_control1->m_width->GetValue() );
		stroke->SetCap( m_control2->m_start_cap->GetValue() , m_control2->m_end_cap->GetValue() );
		stroke->SetJoint( m_control2->m_joint->GetValue() );
		stroke->SetInnerBridgeType( m_control2->m_bridge->GetValue() );
	}
	else if( type == 1 )
	{
		dash->SetStrokeWidth( m_control1->m_width->GetValue() );
		dash->SetCap( m_control2->m_start_cap->GetValue() , m_control2->m_center_cap->GetValue() , m_control2->m_end_cap->GetValue() );
		dash->SetJoint( m_control2->m_joint->GetValue() );
		dash->SetInnerBridgeType( m_control2->m_bridge->GetValue() );
		dash->SetDash( m_control2->m_dash->GetDash() , m_control2->m_dash->GetDashNum() , m_control2->m_dash->GetOffset() );
	}
	isize		size= GetRect().Size();			
	faffine		aff = faffine::GetMove( fvector2( ( float )size.width / 2.0f , ( float )size.height / 2.0f ) );

	iOutlineGen	gen = m_control2->m_gentype->GetValue();
	gen->SetSampleScale( m_control1->m_samplescale->GetValue() );
	m_path->Begin( (iOutline)m_outline , gen );
	if( m_control2->m_edittype->GetValue() == Multi_Edittype )
	{
		m_path->Move( m_pnt[0] , aff * m_control1->m_affine->GetValue() , m_control2->m_loop->GetValue() );
		m_path->Line( 1 , &m_pnt[1] );
		m_path->BezierQ( 2 , &m_pnt[2] );
		m_path->BezierC( 3 , &m_pnt[4] );
		m_path->Arc( m_pnt[7] , 1.0f , m_control1->m_angle->GetValue() );
	}
	else if( m_control2->m_edittype->GetValue() == Line_Edittype )
	{
		m_path->Move( m_pnt[0] , aff * m_control1->m_affine->GetValue() , m_control2->m_loop->GetValue() );
		m_path->Line( 1 , &m_pnt[1] );
	}
	else if( m_control2->m_edittype->GetValue() == Arc_Edittype )
	{
		m_path->Move( m_pnt[6] , aff * m_control1->m_affine->GetValue() , m_control2->m_loop->GetValue() );
		m_path->Arc( m_pnt[7] , 1.0f , m_control1->m_angle->GetValue() );
	}
	else if( m_control2->m_edittype->GetValue() == BezierQ_Edittype )
	{
		m_path->Move( m_pnt[1] , aff * m_control1->m_affine->GetValue() , m_control2->m_loop->GetValue() );
		m_path->BezierQ( 2 , &m_pnt[2] );
	}
	else if( m_control2->m_edittype->GetValue() == BezierC_Edittype )
	{
		m_path->Move( m_pnt[3] , aff * m_control1->m_affine->GetValue() , m_control2->m_loop->GetValue() );
		m_path->BezierC( 3 , &m_pnt[4] );
	}
	m_path->End();

	m_map->Initialize( m_control1->m_anti->GetValue() , p->m_rect );
	m_map->BeginOutline();
	m_map->SetOutline( (iOutline)m_outline , faffine() );
	m_map->EndOutline( m_control1->m_fillrule->GetValue() );

	m_source->SetColor( m_control1->m_color->GetValue() );
	m_renderer->SetBlender( m_control1->m_blender->GetValue() );
	m_renderer->SetPaint( ( iPaint )m_source );
	m_renderer->Render( (iSurfaceDest)p->m_surface , (iEdgemapOutlineInfo)m_map , &p->m_rect , 1 );
	m_time->EndMeasure();

	if( m_control1->m_disp_state->GetOutlineState() == true )
		DrawOutline( (iSurfaceDest)p->m_surface , ( iOutline )m_outline , 1.0f , m_oc );
	if( m_control1->m_disp_state->GetSampleState() == true )
		DrawOutlinePoint( (iSurfaceDest)p->m_surface , ( iOutline )m_outline , m_opc );
	if( m_control1->m_disp_state->GetHandleState() == true )
		DrawHandle( (iSurfaceDest)p->m_surface );
}
//=================================================================================================
void OnSize
		(
		Size_ViewPM*	p
		)
{
	m_control2->Move( irect( ivector2( p->m_rect.xmax - 130 - 1 , 1 ) , isize( 130 , 505 ) ) );
}
//=================================================================================================
void OnLDragStart
		(
		LDragStart_ViewPM*	p
		)
{
	if( m_control1->m_disp_state->GetHandleState() == false )
		return;
	isize		size= GetRect().Size();			
	faffine		aff = faffine::GetMove( fvector2( ( float )size.width / 2.0f , ( float )size.height / 2.0f ) ) * m_control1->m_affine->GetValue();

	int	i;
	for( i = 0 ; i < _countof( m_pnt ) ; i++ )
	{
		fvector2	pnt = aff.Transform( m_pnt[i] );
		irect		rc( ( int )pnt.x - m_handle_r , ( int )pnt.y - m_handle_r , ( int )pnt.x + m_handle_r , ( int )pnt.y + m_handle_r );
		if( true == rc.IsInside( p->m_pos ) )
		{
			m_edit_pnt = i;
			break;
		}
	}
}
//=================================================================================================
void OnLDrag
		(
		LDrag_ViewPM*	p
		)
{
	if( m_edit_pnt == -1 )
		return;

	isize		size	= GetRect().Size();			
	faffine		aff		= faffine::GetMove( fvector2( ( float )size.width / 2.0f , ( float )size.height / 2.0f ) ) * m_control1->m_affine->GetValue();
	faffine		raff	= aff.Inverse();
	
	m_pnt[ m_edit_pnt ]	= raff.Transform( fvector2( ( float )p->m_pos.x , ( float )p->m_pos.y ) );
	RequireUpdate( irect( ivector2( 0 , 0 ) , GetRect().Size() ) , false );
}
//=================================================================================================
void OnLDragEnd
		(
		LDragEnd_ViewPM*	p
		)
{
	m_edit_pnt = -1;
}
//=================================================================================================
void OnLDragCancel
		(
		LDragCancel_ViewPM*	p
		)
{
	m_edit_pnt = -1;
}
// public functions
public:
//=================================================================================================
MainView() : 
		m_handle_r( 5 ) , 
		m_edit_pnt( -1 ) , 
		m_bc( 255 , 255 , 235 ) ,
		m_hlc( 40,121,121) , 
		m_hcc( 40,121,121) , 
		m_oc( 60 , 100 , 60 ) , 
		m_opc( 30,100,100 ) , 
		m_pc( 127 , 191 , 121 , 255 )
{
	m_pnt[0]	= fvector2( -100.0f , -50.0f );
	m_pnt[1]	= fvector2( 0.0f , -100.0f );
	m_pnt[2]	= fvector2( 100.0f , -100.0f );
	m_pnt[3]	= fvector2( 100.0f , 0.0f );
	m_pnt[4]	= fvector2( 100.0f , 50.0f );
	m_pnt[5]	= fvector2( 50.0f , 0.0f );
	m_pnt[6]	= fvector2( 0.0f , 100.0f );
	m_pnt[7]	= fvector2( 0.0f , 0.0f );
}
};

///////////////////////////////////////////////////////////////////////////////////////////////////
// global variable define

///////////////////////////////////////////////////////////////////////////////////////////////////
// global functions define





