
#include "scen.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 <XError.h>
#include "skelmodel.h"


// ==============================  BYTE SWAPPING DATA  ========================================
static byte_swap_code scenery_byte_swapping_data[]=
{
	_begin_bs_array, 1,
	
	// unsigned long flags;
	_4byte,
	
	// file_tag collection_reference_tag;
	_4byte,
	
	// file_tag object_tag;
	// file_tag projectile_tag; // if not NONE, this piece of scenery is a dormant projectile (.sequence_index will be ignored)
	_4byte,
	_4byte,
	
	// short netgame_scoring_type; // invalid if not a flag
	// short flag_number; // invalid if not a flag
	_2byte,
	_2byte,

	// short unused[2];
	2*sizeof(short),
	
	// file_tag projectile_group_tags[MAXIMUM_PROJECTILE_GROUPS_PER_SCENERY_DEFINITION];
	_begin_bs_array, MAXIMUM_PROJECTILE_GROUPS_PER_SCENERY_DEFINITION, _4byte, _end_bs_array,
	
	// short sequence_indexes[MAXIMUM_SEQUENCES_PER_SCENERY_DEFINITION];
	_begin_bs_array, MAXIMUM_SEQUENCES_PER_SCENERY_DEFINITION, _2byte, _end_bs_array,
	
	3*sizeof(short),

	// short model_permutation_delta;
	_2byte,
	
	1*sizeof(short),
	
	// file_tag projectile_group_tags[MAXIMUM_PROJECTILE_GROUPS_PER_SCENERY_DEFINITION];
	_begin_bs_array, MAXIMUM_SEQUENCES_PER_SCENERY_DEFINITION, _4byte, _end_bs_array,
	
	// short unused2[29];
	19*sizeof(short),
	
	// short projectile_group_types[MAXIMUM_PROJECTILE_GROUPS_PER_SCENERY_DEFINITION];
	// short collection_reference_index;
	// short impact_projectile_group_type;
	// short object_type;
	// short projectile_type;
	MAXIMUM_SEQUENCES_PER_SCENERY_DEFINITION*sizeof(short),
	MAXIMUM_PROJECTILE_GROUPS_PER_SCENERY_DEFINITION*sizeof(short),
	4*sizeof(short),
	
	_end_bs_array
};

scenery_definition default_scen =
{
	0,
	-1,
	-1,
	-1,
	0,
	0,
	0, 0,
	-1, -1, -1, -1,
	0, 0, 0,
	0, 0, 0,
	0,
	0,
	-1, -1, -1,
	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0,
	0, 0, 0, 0,
	0,
	0,
	0,
	0,
};


// ==============================  EDIT WINDOW  ========================================
void edit_scen( tag_entry* e )
{
	TscenEditForm* form = new TscenEditForm( e );
	form->AttachWindow( 1021 );
}

void defaultnew_scen( tag_entry *e )
{
	scenery_definition def;
	byte_swap_move_be( "scen", &def, &default_scen, sizeof(scenery_definition), 1, scenery_byte_swapping_data );
	set_entry_data( e, &def, sizeof(def), false );
}


void update_scen( tag_entry *e )
{
	int i, j, k;
	
	for (;;)
	{
		int version = get_entry_version( e );
		switch (version)
		{
			case 1: {
					set_entry_version( e, 2 ); // no changes!
				} break;
				
			case 2:
				return;
			default:
				Assert(0);
				return;
		}
	}
}


void dependency_scen( tag_entry *e )
{
	scenery_definition def;
	read_scenery_definition( &def, e );
	int i;
	bool skel = def.flags & _scenery_is_skelmodel_flag;
	add_tag_dependency( 'obje', def.object_tag );
	add_tag_dependency( 'proj', def.projectile_tag );
	for (i = 0; i < NUMBER_OF_PROJECTILE_GROUPS_PER_SCENERY_DEFINITION; ++i)
	{
		add_tag_dependency( 'prgr', def.projectile_group_tags[i] );
	}
	if (skel)
	{
		for (i = 0; i < NUMBER_OF_SEQUENCES_PER_SCENERY_DEFINITION; ++i)
		{
			add_tag_dependency( 'skmd', def.skelmodel_tags[i] );
		}
	}
	else
	{
		add_tag_dependency( skel ? 'skmd' : 'core', def.collection_reference_tag );
	}
}


// ==============================  READ TAG DATA  ========================================
bool read_scenery_definition( scenery_definition* def, tag_entry* e )
{
	return load_tag_data_into_struct( "scen", e, def, SIZEOF_STRUCT_SCENERY_DEFINITION, 1, scenery_byte_swapping_data);
}


// ==============================  SAVE TAG DATA  ========================================
bool save_scenery_definition( scenery_definition* def, tag_entry* e )
{
	return save_tag_data_from_struct( "scen", e, def, SIZEOF_STRUCT_SCENERY_DEFINITION, 1, scenery_byte_swapping_data);
}


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


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

	return save_scenery_definition( def, e );
}


// ==============================  DISPATCH  ========================================
BEGINDISPATCH(TscenEditForm,TTagEditForm)
	DISPATCHTABLE(KXGControlClick,TscenEditForm::DoControlClick)
ENDDISPATCH


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

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

}


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

	tag_entry* e;
	tag new_id;
	
	switch( arg )
	{
		case 12101:			// Choose a tag
			new_id = pick_tag_of_type('core', GetTag( 12101 ), fEntry );
			if(new_id != 0) SetTag( 12101, 'core', new_id );
		break; 
		case 12102:			// Open tag window
			e = get_entry('core', GetTag( 12101 ) );
			if(e) TRevengeApp::OpenItem( e );
		break;

		case 12103:			// Choose a tag
			new_id = pick_tag_of_type('proj', GetTag( 12103 ), fEntry );
			if(new_id != 0) SetTag( 12103, 'proj', new_id );
		break; 
		case 12104:			// Open tag window
			e = get_entry('proj', GetTag( 12103 ) );
			if(e) TRevengeApp::OpenItem( e );
		break;

		case 12105:			// Choose a tag
			new_id = pick_tag_of_type('obje', GetTag( 12105 ), fEntry );
			if(new_id != 0) SetTag( 12105, 'obje', new_id );
		break; 
		case 12106:			// Open tag window
			e = get_entry('obje', GetTag( 12105 ) );
			if(e) TRevengeApp::OpenItem( e );
		break;

		case 12108:			// Choose a tag
			new_id = pick_tag_of_type('prgr', GetTag( 12108 ), fEntry );
			if(new_id != 0) SetTag( 12108, 'prgr', new_id );
		break; 
		case 12109:			// Open tag window
			e = get_entry('prgr', GetTag( 12108 ) );
			if(e) TRevengeApp::OpenItem( e );
		break;

		case 12110:			// Choose a tag
			new_id = pick_tag_of_type('prgr', GetTag( 12110 ), fEntry );
			if(new_id != 0) {
				SetTag( 12110, 'prgr', new_id );
			}
		break; 
		case 12111:			// Open tag window
			e = get_entry('prgr', GetTag( 12110 ) );
			if(e) TRevengeApp::OpenItem( e );
		break;
		
		case 12001:		// undamaged skelmodel
			new_id = pick_tag_of_type('skmd', GetTag( arg ), fEntry );
			if (new_id != 0) {
				SetTag( arg, 'skmd', new_id );
				RebuildStatePopup( 12112, new_id, GetInt(12112)-1 );
			}
			break;
		case 12002:
			e = get_entry('skmd', GetTag( arg ) );
			if (e) TRevengeApp::OpenItem( e );
			break;

		case 12003:		// ruined skelmodel
			new_id = pick_tag_of_type('skmd', GetTag( arg ), fEntry );
			if (new_id != 0) {
				SetTag( arg, 'skmd', new_id );
				RebuildStatePopup( 12114, new_id, GetInt(12114)-1 );
			}
			break;
		case 12004:
			e = get_entry('skmd', GetTag( arg ) );
			if (e) TRevengeApp::OpenItem( e );
			break;

		default:
			return -1;
	}

	return 0;
}

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


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


// ========================================  TAG NEEDS UPDATING  ==================================================
bool TscenEditForm::NeedCommit()
{
	GetValues();
	return tag_data_needs_update( "scen", fEntry, &def, SIZEOF_STRUCT_SCENERY_DEFINITION, 1, scenery_byte_swapping_data);
}

		
// ========================================  SET INTERFACE VALUES  ==================================================
void TscenEditForm::SetValues()
{
	SetFlag( 12000, FALSE );
	if(def.flags&_scenery_is_skelmodel_flag ) SetFlag( 12000, TRUE );
	
	if (def.flags & _scenery_is_skelmodel_flag) {
		SetTag( 12101, 'core', def.collection_reference_tag );
	} else {
		SetTag( 12101, 'core', def.collection_reference_tag );
	}
	SetTag( 12103, 'proj', def.projectile_tag );
	SetTag( 12105, 'obje', def.object_tag );
	SetTag( 12108, 'prgr', def.projectile_group_tags[_scenery_impact_projectile_group] );
	SetTag( 12110, 'prgr', def.projectile_group_tags[_scenery_detonation_projectile_group] );
	
	RebuildStatePopup( 12112, def.skelmodel_tags[_scenery_sequence_undamaged], def.sequence_indexes[_scenery_sequence_undamaged] );
	RebuildStatePopup( 12114, def.skelmodel_tags[_scenery_sequence_ruined], def.sequence_indexes[_scenery_sequence_ruined] );
	
	XGPopControl* pList3;
	pList3 = dynamic_cast<XGPopControl*>(GetWindow()->FindViewByID( 12117 ));
	assert(pList3);
	pList3->DeleteAll();
	pList3->Insert(0, "None");
	pList3->Insert(1, "Body Count");
	pList3->Insert(2, "Steal the Bacon");
	pList3->Insert(3, "Last Man on the Hill");
	pList3->Insert(4, "Scavenger Hunt");
	pList3->Insert(5, "Flag Rally");
	pList3->Insert(6, "Capture the Flag");
	pList3->Insert(7, "Balls on Parade");
	pList3->Insert(8, "Territories");
	pList3->Insert(9, "Captures");
	pList3->Insert(10, "King of the Hill");
	pList3->Insert(11, "Rugby");
	pList3->Insert(12, "Assassination");
	pList3->Insert(13, "Hunting");
	pList3->Insert(14, "None");
	pList3->SetValue( def.valid_netgame_scoring_type );


	SetFlag( 12116, FALSE );
	if(def.flags&_scenery_is_netgame_flag_flag ) SetFlag( 12116, TRUE );
	SetFlag( 12119, FALSE );
	if(def.flags&_scenery_is_solid_flag ) SetFlag( 12119, TRUE );
	SetFlag( 12120, FALSE );
	if(def.flags&_scenery_has_random_facing_flag ) SetFlag( 12120, TRUE );
	SetFlag( 12121, FALSE );
	if(def.flags&_scenery_is_large_object_flag ) SetFlag( 12121, TRUE );
	SetFlag( 12122, FALSE );
	if(def.flags&_scenery_respects_monster_visibility_flag ) SetFlag( 12122, TRUE );
	SetFlag( 12123, FALSE );
	if(def.flags&_scenery_adjusts_model_permutation_flag ) SetFlag( 12123, TRUE );
	SetFlag( 12124, FALSE );
	if(def.flags&_scenery_animates_flag ) SetFlag( 12124, TRUE );
	SetFlag( 12125, FALSE );
	if(def.flags&_scenery_marks_terrain_impassable_flag ) SetFlag( 12125, TRUE );
	SetFlag( 12126, FALSE );
	if(def.flags&_scenery_vitality_affects_model_animation_flag ) SetFlag( 12126, TRUE );
	SetFlag( 12127, FALSE );
	if(def.flags&_scenery_destruction_starts_model_animation_flag ) SetFlag( 12127, TRUE );
	SetFlag( 12008, FALSE );
	if(def.flags&_scenery_uses_tree_physics_flag ) SetFlag( 12008, TRUE );
	SetFlag( 12009, FALSE );
	if(def.flags&_scenery_uses_tree_physics_when_ruined_flag ) SetFlag( 12009, TRUE );
	SetFlag( 12128, FALSE );
	if(def.flags&_scenery_can_be_activated_flag ) SetFlag( 12128, TRUE );
	SetFlag( 12129, FALSE );
	if(def.flags&_scenery_can_be_deactivated_flag ) SetFlag( 12129, TRUE );
	SetFlag( 12130, FALSE );
	if(def.flags&_scenery_is_initially_active_flag ) SetFlag( 12130, TRUE );

	SetInt( 12107, def.model_permutation_delta );
	SetInt( 12118, def.netgame_flag_number );
	
	SetTag( 12001, 'skmd', def.skelmodel_tags[_scenery_sequence_undamaged] );
	SetTag( 12003, 'skmd', def.skelmodel_tags[_scenery_sequence_ruined] );
}


// ========================================  GET INTERFACE VALUES  ==================================================
void TscenEditForm::GetValues()
{

	def.collection_reference_tag = GetTag( 12101 );
	def.projectile_tag = GetTag( 12103 );
	def.object_tag = GetTag( 12105 );
	def.projectile_group_tags[_scenery_impact_projectile_group] = GetTag( 12108 );
	def.projectile_group_tags[_scenery_detonation_projectile_group] = GetTag( 12110 );

	XGPopControl* pList1;
	pList1 = dynamic_cast<XGPopControl*>(GetWindow()->FindViewByID( 12112 ));
	assert(pList1);
	def.sequence_indexes[_scenery_sequence_undamaged] = pList1->GetValue() - 1;

	XGPopControl* pList2;
	pList2 = dynamic_cast<XGPopControl*>(GetWindow()->FindViewByID( 12114 ));
	assert(pList2);
	def.sequence_indexes[_scenery_sequence_ruined] = pList2->GetValue() - 1;

	XGPopControl* pList3;
	pList3 = dynamic_cast<XGPopControl*>(GetWindow()->FindViewByID( 12117 ));
	assert(pList3);
	def.valid_netgame_scoring_type = pList3->GetValue();
	
	def.skelmodel_tags[_scenery_sequence_undamaged] = GetTag( 12001 );
	def.skelmodel_tags[_scenery_sequence_ruined] = GetTag( 12003 );

	def.flags = 0;
	if(GetFlag( 12000 )) def.flags |= _scenery_is_skelmodel_flag;
	if(GetFlag( 12116 )) def.flags |= _scenery_is_netgame_flag_flag;
	if(GetFlag( 12119 )) def.flags |= _scenery_is_solid_flag;
	if(GetFlag( 12120 )) def.flags |= _scenery_has_random_facing_flag;
	if(GetFlag( 12121 )) def.flags |= _scenery_is_large_object_flag;
	if(GetFlag( 12122 )) def.flags |= _scenery_respects_monster_visibility_flag;
	if(GetFlag( 12123 )) def.flags |= _scenery_adjusts_model_permutation_flag;
	if(GetFlag( 12124 )) def.flags |= _scenery_animates_flag;
	if(GetFlag( 12125 )) def.flags |= _scenery_marks_terrain_impassable_flag;
	if(GetFlag( 12126 )) def.flags |= _scenery_vitality_affects_model_animation_flag;
	if(GetFlag( 12127 )) def.flags |= _scenery_destruction_starts_model_animation_flag;
	if(GetFlag( 12008 )) def.flags |= _scenery_uses_tree_physics_flag;
	if(GetFlag( 12009 )) def.flags |= _scenery_uses_tree_physics_when_ruined_flag;
	if(GetFlag( 12128 )) def.flags |= _scenery_can_be_activated_flag;
	if(GetFlag( 12129 )) def.flags |= _scenery_can_be_deactivated_flag;
	if(GetFlag( 12130 )) def.flags |= _scenery_is_initially_active_flag;

	def.model_permutation_delta = GetInt( 12107 );
	def.netgame_flag_number = GetInt( 12118 );

}


void TscenEditForm::RebuildStatePopup( int view_id, tag tag_id, int anim_num )
{
	XGPopControl* pList2;
	pList2 = dynamic_cast<XGPopControl*>(GetWindow()->FindViewByID( view_id ));
	assert(pList2);
	pList2->DeleteAll();
	XGStringList states;
	char buf[64];
	if (ExtractSKMDNames( get_entry( 'skmd', tag_id ), &states )) {
		pList2->Insert(0, "None");
		for (int i = 0; i < states.GetNumStrings(); ++i) {
			states.GetString( i, buf );
			pList2->Insert( i+1, buf );
		}
	} else {
		states.GetString( 0, buf );
		pList2->Insert(0, buf );
	}
	pList2->SetValue( anim_num + 1 );
}

