#include "prgr.h"

#ifndef PandaWave_RESOURCES
#include "RevengeResources.h"
#endif

#include "RevengeApp.h"
#include <XMessages.h>
#include "tagpick.h"
#include <assert.h>
#include <XPopup.h>
#include <XWindow.h>
#include <XDialog.h>
#include <XButtons.h>
#include <XList.h>
#include "formatters.h"

static long EditPartProc( XGDialog *dlog, void *data, long msg, long arg, void *parg );

// ==============================  BYTE SWAPPING DATA  ========================================
static byte_swap_code projectile_group_definition_byte_swapping_data[]=
{
	_begin_bs_array, 1,
	
	// unsigned long flags;
	_4byte,
	
	// short number_of_parts;
	_2byte,
	
	// word pad;
	sizeof(word),

	// file_tag mesh_effect_tag;
	// file_tag sound_tag;
	// file_tag local_projectile_group_tag;
	_4byte,
	_4byte,
	_4byte,
	
	// short unused[3];
	3*sizeof(short),
	
	// short local_projectile_group_type;
	// short mesh_effect_type;
	// short sound_index;
	3*sizeof(short),
	
	// struct projectile_group_part_definition parts[MAXIMUM_NUMBER_OF_PARTS_PER_PROJECTILE_GROUP];
	
		_begin_bs_array, MAXIMUM_NUMBER_OF_PARTS_PER_PROJECTILE_GROUP,
		
		// file_tag projectile_tag;
		_4byte,

		// unsigned long flags;
		_4byte,
			
		// short count_lower_bound, count_delta;
		// short_fixed position_lower_bound, position_delta;
		_2byte, _2byte,
		_2byte, _2byte,

		// short obsolete[2];
		2*sizeof(short),
		
		// fixed_fraction appearing_fraction; // chance that this part will actually be created
		_2byte,
		
		// short unused[4];
		4*sizeof(short),
		
		// short projectile_type;
		1*sizeof(short),
		
		_end_bs_array,
	
	_end_bs_array
};

projectile_group_definition default_prgr =
{
	0,
	0,
	0,
	-1,
	-1,
	-1,
	0, 0, 0,
	0,
	0,
	0,
	// parts
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};


// ==============================  EDIT WINDOW  ========================================
void edit_prgr( tag_entry* e )
{
	TprgrEditForm* form = new TprgrEditForm( e );
	form->AttachWindow( 1019 );
}

void defaultnew_prgr( tag_entry *e )
{
	projectile_group_definition def;
	byte_swap_move_be( "prgr", &def, &default_prgr, sizeof(projectile_group_definition), 1, projectile_group_definition_byte_swapping_data );
	set_entry_data( e, &def, sizeof(def), false );
}


void dependency_prgr( tag_entry *e )
{
	projectile_group_definition def;
	read_projectile_group_definition( &def, e );
	add_tag_dependency( 'meef', def.mesh_effect_tag );
	add_tag_dependency( 'soun', def.sound_tag );
	add_tag_dependency( 'lpgr', def.local_projectile_group_tag );
	for (int i = 0; i < def.number_of_parts; ++i)
	{
		add_tag_dependency( 'proj', def.parts[i].projectile_tag );
	}
}

// ==============================  READ TAG DATA  ========================================
bool read_projectile_group_definition( projectile_group_definition* def, tag_entry* e )
{
	return load_tag_data_into_struct( "prgr", e, def, SIZEOF_STRUCT_PROJECTILE_GROUP_DEFINITION, 1, projectile_group_definition_byte_swapping_data);
}


// ==============================  SAVE TAG DATA  ========================================
bool save_projectile_group_definition( projectile_group_definition* def, tag_entry* e )
{
	return save_tag_data_from_struct( "prgr", e, def, SIZEOF_STRUCT_PROJECTILE_GROUP_DEFINITION, 1, projectile_group_definition_byte_swapping_data);
}


// ==============================  READ TAG DATA (WITH ID) ========================================
bool read_projectile_group_definition( projectile_group_definition* def, tag id )
{
	tag_entry* e;
	
	assert( def );
	
	e = get_entry( 'prgr', id );
	if( 0 == e ) {
		return FALSE;
	}
	
	return read_projectile_group_definition( def, e );	
}


// ==============================  SAVE TAG DATA (WITH ID) ========================================
bool save_projectile_group_definition( projectile_group_definition* def, tag id )
{
	tag_entry* e;
	
	assert( def );
	
	e = get_entry( 'prgr', id );
	if( 0 == e ) {
		return FALSE;
	}

	return save_projectile_group_definition( def, e );
}


// ==============================  DISPATCH  ========================================
BEGINDISPATCH(TprgrEditForm,TTagEditForm)
	DISPATCHTABLE(KXGControlClick,TprgrEditForm::DoControlClick)
	DISPATCHTABLE(KXGListValue,TprgrEditForm::DoListSelect)
ENDDISPATCH


TprgrEditForm::TprgrEditForm( struct tag_entry *e ) : TTagEditForm( e )
{
}

// ==============================  INITIALIZE FORM =======================================
void TprgrEditForm::DoFormInitialize()
{
	TTagEditForm::DoFormInitialize();

}


// ==============================  INPUT HANDLING  ========================================
long TprgrEditForm::DoControlClick( long arg, void *ptr )
{
#ifdef __MWERKS__
	#pragma unused(ptr)
#endif

	XGListControl *pList = dynamic_cast<XGListControl *>(GetWindow()->FindViewByID( 11907 ));

	tag_entry* e;
	tag new_id;
	
	int ii;
	
	switch( arg )
	{
		case 11901:			// Choose a tag
			new_id = pick_tag_of_type('meef', GetTag( 11901 ), fEntry );
			if(new_id != 0) SetTag( 11901, 'meef', new_id );
		break; 
		
		case 11902:			// Open tag window
			e = get_entry('meef', GetTag( 11901 ) );
			if(e) TRevengeApp::OpenItem( e );
		break;
		
		case 11903:			// Choose a tag
			new_id = pick_tag_of_type('soun', GetTag( 11903 ), fEntry );
			if(new_id != 0) SetTag( 11903, 'soun', new_id );
		break; 
		
		case 11904:			// Open tag window
			e = get_entry('soun', GetTag( 11903 ) );
			if(e) TRevengeApp::OpenItem( e );
		break;
		
		case 11905:			// Choose a tag
			new_id = pick_tag_of_type('lpgr', GetTag( 11905 ), fEntry );
			if(new_id != 0) SetTag( 11905, 'lpgr', new_id );
		break; 
		
		case 11906:			// Open tag window
			e = get_entry('lpgr', GetTag( 11905 ) );
			if(e) TRevengeApp::OpenItem( e );
		break;
		
		// ======================================================================
		case 11908:			// Add new Projectile Group Part
			assert( def.number_of_parts < MAXIMUM_NUMBER_OF_PARTS_PER_PROJECTILE_GROUP );
			
			memset( &def.parts[def.number_of_parts], 0x00, sizeof(projectile_group_part_definition) );
			def.parts[def.number_of_parts].projectile_tag = -1;
			
			if( XGDialog::ModalDialog( KWindowPRGRPartSettings, EditPartProc, &def.parts[def.number_of_parts] ) )
				def.number_of_parts++;
				
			SetValues();
			
		break;
		
		case 11909:			// Edit Projectile Group Part
			assert( def.number_of_parts < MAXIMUM_NUMBER_OF_PARTS_PER_PROJECTILE_GROUP );
			
			if( pList->GetValue() >= 0 && pList->GetValue() < def.number_of_parts )
			{
				projectile_group_definition new_part_def;
				
				memcpy( &new_part_def, &def.parts[pList->GetValue()], sizeof(projectile_group_definition) );
				
				if( XGDialog::ModalDialog( KWindowPRGRPartSettings, EditPartProc, &new_part_def ) )
					memcpy( &def.parts[pList->GetValue()], &new_part_def, sizeof(projectile_group_definition) );
			}
				
			SetValues();
			
		break;
		
		case 11910:			// Duplicate Projectile Group Part
			assert( def.number_of_parts < MAXIMUM_NUMBER_OF_PARTS_PER_PROJECTILE_GROUP );
			
			def.parts[def.number_of_parts] = def.parts[pList->GetValue()];
			if( XGDialog::ModalDialog( KWindowPRGRPartSettings, EditPartProc, &def.parts[def.number_of_parts] ) )
				def.number_of_parts++;
				
			SetValues();
			
		break;
		
		case 11911:			// Delete Projectile Group Part
			assert( def.number_of_parts > 0 );
			
			for( ii = pList->GetValue(); ii < def.number_of_parts - 1; ii++ )
			{
				def.parts[ii] = def.parts[ii + 1];
			}
			
			memset( &def.parts[def.number_of_parts], 0x00, sizeof(projectile_group_part_definition) );
			def.number_of_parts--;
			
			SetValues();
			
		break;
		
		default:
			return -1;
	}
	
	UpdatePartControls();

	return 0;
}

long TprgrEditForm::DoListSelect( int arg, void *ptr )
{
#ifdef __MWERKS__
	#pragma unused(ptr)
#endif

	XGListControl *pList = dynamic_cast<XGListControl *>(GetWindow()->FindViewByID( 11907 ));
	int sel;
	
	sel = GetInt( arg );
	
	switch( arg )
	{
		case 11907: // projectile list
			UpdatePartControls();
			return 0;
	}
	
	return -1;
}

void TprgrEditForm::UpdatePartControls()
{
	XGListControl *pList = dynamic_cast<XGListControl *>(GetWindow()->FindViewByID( 11907 ));
	XGCommandButton *pButton;

	// Add
	pButton = dynamic_cast<XGCommandButton *>(GetWindow()->FindViewByID( 11908 ));
	pButton->SetEnabled( (def.number_of_parts < MAXIMUM_NUMBER_OF_PARTS_PER_PROJECTILE_GROUP) ? true : false );
	
	// Edit
	pButton = dynamic_cast<XGCommandButton *>(GetWindow()->FindViewByID( 11909 ));
	pButton->SetEnabled( (pList->GetValue() >= 0 && pList->GetValue() < def.number_of_parts) ? true : false );
	
	// Duplicate
	pButton = dynamic_cast<XGCommandButton *>(GetWindow()->FindViewByID( 11910 ));
	pButton->SetEnabled( ((def.number_of_parts < MAXIMUM_NUMBER_OF_PARTS_PER_PROJECTILE_GROUP) && (pList->GetValue() != -1)) ? true : false );

	// Delete
	pButton = dynamic_cast<XGCommandButton *>(GetWindow()->FindViewByID( 11911 ));
	pButton->SetEnabled( ((def.number_of_parts > 0) && (pList->GetValue() != -1)) ? true : false );
}

// ========================================  SAVE TO TAG  ==================================================
void TprgrEditForm::CommitToTag()
{
	GetValues();
	save_projectile_group_definition( &def, fEntry );
}


// ========================================  RELOAD TAG  ==================================================
void TprgrEditForm::ReloadTag()
{
	read_projectile_group_definition( &def, fEntry );
	SetValues();
}


// ========================================  TAG NEEDS UPDATING  ==================================================
bool TprgrEditForm::NeedCommit()
{
	GetValues();
	return tag_data_needs_update( "prgr", fEntry, &def, SIZEOF_STRUCT_PROJECTILE_GROUP_DEFINITION, 1, projectile_group_definition_byte_swapping_data);
}


// ========================================  SET INTERFACE VALUES  ==================================================
void TprgrEditForm::SetValues()
{
	int ii;
	
	SetTag( 11901, 'meef', def.mesh_effect_tag );
	SetTag( 11903, 'soun', def.sound_tag );
	SetTag( 11905, 'lpgr', def.local_projectile_group_tag );
	
	XGListControl *pList = dynamic_cast<XGListControl *>(GetWindow()->FindViewByID( 11907 ));
	pList->DeleteAll();
	
	for( ii = 0; ii < def.number_of_parts; ii++ )
	{
		pList->Insert( ii, get_entry_name( get_entry( 'proj', def.parts[ii].projectile_tag ) ) );
	}
	
	pList->SetValue( def.number_of_parts - 1 );
	
	DoListSelect( 11907, NULL );
}


// ========================================  GET INTERFACE VALUES  ==================================================
void TprgrEditForm::GetValues()
{
	def.mesh_effect_tag = GetTag( 11901 );
	def.sound_tag = GetTag( 11903 );
	def.local_projectile_group_tag = GetTag( 11905 );
}

static long EditPartProc( XGDialog *dlog, void *data, long msg, long arg, void *parg )
{
	if( !dlog )
		return -1;
	
	projectile_group_part_definition *part = (projectile_group_part_definition *)data;
	
	switch( msg )
	{
		case KXGDialogMessage:
		{
			switch( arg )
			{
				case KXGDMInitDialog:
				{
					tag_entry *e = get_entry( 'proj', part->projectile_tag );
					dlog->SetText( 101, e ? get_entry_name( e ) : tagstr( part->projectile_tag ) );

					SetInt( dlog, 103, part->count_lower_bound );
					SetInt( dlog, 104, get_upper_bound( part->count_lower_bound, part->count_delta ) );
					SetShortFixed( dlog, 105, part->position_lower_bound );
					SetShortFixed( dlog, 106, get_upper_bound( part->position_lower_bound, part->position_delta ) );
					SetPercentage( dlog, 107, part->appearing_fraction );
					
					dlog->SetValue( 108, (part->flags & _projectile_group_part_is_on_ground_flag) );
					dlog->SetValue( 109, (part->flags & _projectile_group_part_is_central_flag) );
					
					return 0;
				}
				
				default:
					break;
			}
		}
		case KXGControlClick:
		{
			switch( arg )
			{
				case 1001: // ok
				{
					part->count_lower_bound = GetInt( dlog, 103 );
					part->count_delta = get_delta( (long)GetInt( dlog, 103 ), (long)GetInt( dlog, 104 ) );
					part->position_lower_bound = GetShortFixed( dlog, 105 );
					part->position_delta = get_delta( GetShortFixed( dlog, 105 ), GetShortFixed( dlog, 106 ) );
					part->appearing_fraction = GetPercentage( dlog, 107 );
					
					dlog->GetValue( 108 ) ? part->flags |= _projectile_group_part_is_on_ground_flag : part->flags &= ~_projectile_group_part_is_on_ground_flag;
					dlog->GetValue( 109 ) ? part->flags |= _projectile_group_part_is_central_flag : part->flags &= ~_projectile_group_part_is_central_flag;
					
					dlog->EndDialog( 1 );
					return 0;
				}
				case 1002: // cancel
				{
					dlog->EndDialog( 0 );
					return 0;
				}
				case 101: // pick tag
				{
					tag new_proj = pick_tag_of_type( 'proj', part->projectile_tag, (tag_file *)0 );
					if( new_proj )
						part->projectile_tag = new_proj;
					
					tag_entry *e = get_entry( 'proj', part->projectile_tag );
					dlog->SetText( 101, e ? get_entry_name( e ) : tagstr( part->projectile_tag ) );
					
					return 0;
				}
				case 102: // open tag
				{
					tag_entry *e = get_entry( 'proj', part->projectile_tag );
					if( e )
						TRevengeApp::OpenItem( e );
						
					return 0;
				}
				
				case 108: // flags
				case 109:
				{
					dlog->SetValue( arg, !dlog->GetValue( arg ) );
					return 0;
				}
				
				defualt:
					break;
			}
		}
		
		default:
			break;
	}
	
	return -1;
}
