/*
 * Bugs:
 *
 */

/*
 * Changelog v1.1 -> v1.2
 *
 ** 23/04/10 **
 * - NEW: Character Portrait
 * - NEW: Add Tooltips to Items
 * - NEW: Update Item Information to be current as of Demigod v1.2
 * - NEW: Rip Oculus Ability Images and Portrait
 * - NEW: Rip Demon Assassin Images and Portrait
 * - NEW: Add Oculus Demigod attributes (Base Stats, Level Up Stats)
 * - NEW: Add Demon Assassin Demigod attributes (Base Stats, Level Up Stats)
 *
 ** 24/04/10 **
 * - NEW: Add Forked Dependancies
 * - NEW: Sell/Remove Abilities
 * - NEW: Add Tooltips to Abilities
 * - NEW: Checked changelogs, have determined all current abilities and stats should be up-to-date
 * - NEW: Added Passive Abilities to Calculations
 * - NEW: Added Use/Proc Abilities to Calculations
 * - NEW: Save Builds in URL!
 * - NEW: Add Demon Assassin Abilities
 * - NEW: Add Oculus Abilities
 * - BUG: Fix Skill Points when changing DG's
 * - BUG: Fix Skill Points when Selling Abilities
 * - BUG: Fix Tech-Tree loading bug
 * - BUG: Fix Calculator
 * - BUG: Fix Tech-Tree Latency
 * - BUG: Fix Calculator Hiding Pages Bug
 * - BUG: Fix Oculus/Demon Assassin not allow Class Favor Items
 * - BUG: Fixed Ability Stacking
 * - BUG: When you restore a saved build, the tooltips for items are broken
 * - BUG: Generals can buy Assassin Favor Items etc even though they are greyed out
 * - BUG: Fix Tooltip overflow
 ** 25/04/10 **
 * - NEW: Added Idols to User Interface
 * - NEW: Added Idols Store
 * - NEW: Added Shift-Click to Abilities Page to buy regardless of dependencies
 * - BUG: Fixed a few typos in abilities
 * - BUG: Bad ordering in Idols Shop
 */

/*
 * Additional Features Planned after v1.2:
 * - Improved Ability Tooltips to include "Hidden" information
 * - Improved calculator to include more statistics etc
 * - Ability to Copy/Paste Item/Ability Information, somehow.
 * - Allow abilities/items to be toggled on and off if they are Use or Proc type events rather than passive (Done, should just need images and testing)
 */

/*
 * Currently Just A Pipe Dream:
 * - Ability to Compare/Swap between multiple builds at once easily
 * - Ability to create Strategies that link to one or more builds along with additional information and replays
 * - Community Features such as comments/ratings for builds/strategies, Top/New Builds
 */
 
/*
 * Acknowledgements:
 * - Credit to http://www.aradsociety.com/planner/ for the url encoding functions used while saving state.
 */
 
(function(){

	var config = {
		level_cap: 20,
		views: {
			gold: '#gold_spent',
			favor: '#favor_spent',
			demigod_select: '#demigod_select',
			level_select: '#level_select',
			tech_tree: '#ability_tech_tree',
			shop: '#shop',
			skills_left: '#skills_left',
			reset_skills: '#reset_skills',
			portrait: '#demigod_icon',
			calculator: '#character_statistics'
		},
		prefix: {
			slot: 'slot_',
			shop_item: 'shop_item_'
		},
		classes: {
			skill_bought: 'skill_bought'
		}
	};

	var active = {
		page: 'news',
		shift_down: false,
		demigod: {},
		gold: 0,
		favor: 0,
		skill_points: 1,
		slots: { 
			i1: { type: 'item', item: {} }, 
			i2: { type: 'item', item: {} }, 
			i3: { type: 'item', item: {} }, 
			i4: { type: 'item', item: {} }, 
			i5: { type: 'item', item: {} }, 
			t1: { type: 'trinket', item: {} }, 
			t2: { type: 'trinket', item: {} }, 
			t3: { type: 'trinket', item: {} }, 
			f1: { type: 'favor', item: {} },
			g1: { type: 'idol_minotaur', item: {} }, 
			g2: { type: 'idol_archer', item: {} }, 
			g3: { type: 'idol_priest', item: {} } 
		},
		abilities: {},
		effects: {}
	};
	var profiles = [];


	var demigoddb = {};
	var itemsdb = {};
	var abilitiesdb = {};

	/*
	 * Views
	 */

	function get_view( view_id ) {
		return $( config.views[ view_id ] );
	}

	function update_view( view_id , content ) {
		$( config.views[ view_id ] ).html( content );
	}

	
	
	/*
	 * Utility Functions
	 */

	function syncronous_json( url, callback ) {
		$.ajax({
		  url: url,
		  dataType: 'json',
		  async: false,
		  success: callback
		});
	}

	
	
	
	/*
	 * Update State
	 */

	function load_page( page_id ) 
	{
		if ( page_id ) 
		{
			if ( active.page != page_id ) {
				active.page = page_id;
				update_hash();
			}
			
			if ( page_id.split('-').length > 1 ) {
				var split = page_id.split('-');
				page_id = split[0];
				if ( page_id == "items" ) {
					load_store( split[1] );
				}
			}

			$('.page').hide();
			$("#page_" + page_id ).show();
		}
	}

	function load_store( store_id ) {	
		active.page = active.page.split('-')[0] + "-" + store_id;
		update_hash();
		
		update_view('shop', "Loading Items...<br /><br /><center><img src='images/loading.gif' /></center>" );
		$.ajax({
			type: "POST",
			url: "rpc/store_html.php",
			data: "store_id=" + store_id,
			success: function(html){ update_view('shop', html); refresh_ui(); }
		});
	}

	function load_statistics() 
	{
		var cs = $('#character_statistics');
		if ( cs.is(':visible'))
		{
			cs.prepend("<div class='loading'><img src='images/loading_spinner.gif' /></div>");
			$.ajax({
				type: "POST",
				url: "rpc/statistics_html.php",
				data: "state=" + reduce_state( active ),
				success: function(html){ cs.html(html); update_effects(); }
			 });
		 }
	}
	
	
	
	
	/*
	 * User Interface
	 */

	function setup_ui()
	{
		/* Load JSON from Server */
		
		get_demigod_db();	// Loads all Demigods
		get_items_db();		// Loads all Items
		get_abilities_db();	// Loads all Abilities

		// Load Demigod Select
		$.each( demigoddb, function(demigod_id, demigod) {
			var new_demigod = $("<option/>").val( demigod.id ).text( demigod.name );
			get_view( 'demigod_select' ).append( new_demigod );
		});

		// Load Level Select
		for ( var i = 1; i <= config.level_cap; i++ ) {
			get_view( 'level_select' ).append( $("<option/>").val( i ).text( i ) );
		}
		
		// Load Default Store
		load_store( 1 );
	}
	
	
	function refresh_ui() 
	{
		// Select the Demigod and Level
		get_view( 'demigod_select' ).val( get_demigod_attr( 'id' ) );
		get_view( 'level_select' ).val( get_demigod_attr( 'level' ) );

		// Loop over items and set slots
		update_item_slots();

		// Loop over the tech tree of abilities
		update_tech_tree();
		
		// Update Skill Points
		update_skill_points();
		
		// Update Spent Amounts
		update_spent();
		
		// Loop over store and hide/show items
		update_shop();
		
		// Update Statistics
		load_statistics();
		
		// Update Hash
		update_hash();
	}
	
	function update_item_slots() 
	{
		$.each( active.slots, function( slot_id, slot ) {
			if ( !$.isEmptyObject( slot.item ) ) 
			{
				if ( active.demigod.toon_class != "general" && ( slot_id == "g1" || slot_id == "g2" || slot_id == "g3" ) ) {
					set_slot_item( slot_id, {} );
					return true;
				} 

				if ( !active.slots[ slot_id ].tooltip ) {
					active.slots[ slot_id ].tooltip = slot.item.tooltip;
				}
				
				$('#' + config.prefix.slot + slot_id )
					.removeClass()
					.addClass('item_slot')
					.addClass( slot.item.store_type )
					.addClass("sprite-" + slot.item.imgname )
					.addClass('item_slot_occupied')	
					.skeletonTip( active.slots[ slot_id ].tooltip );
			} 
			else 
			{
				active.slots[ slot_id ].tooltip = "";
				$('#' + config.prefix.slot + slot_id )
					.removeClass()
					.addClass('item_slot')
					.addClass('ui')
					.addClass('sprite-' + slot.type + '_slot')
					.skeletonTipDestroy();
			}
		});
	}
	
	function update_tech_tree() 
	{
		get_view( 'tech_tree' ).find('.ability_tech').each( function() {

			var ability = get_ability_data( $(this).attr('skill_id') );
		
			var vhas_ability = has_ability( ability );
			var vcheck_ability_availability = check_ability_availability( ability );
			var vcount_abilities = calculate_skill_points();
			
			$(this).skeletonTip($(this).find(".tooltip").html());

			if ( vhas_ability && vcheck_ability_availability ) {
				update_ability_state( $(this), 'bought' );
			}
			
			else if ( vhas_ability && !vcheck_ability_availability ) {
				remove_ability( ability );
				update_ability_state( $(this), 'unavailable' );
			}

			else if ( !vhas_ability && vcheck_ability_availability && vcount_abilities > 0 ) {
				update_ability_state( $(this), 'available' );
			} 

			else {
				update_ability_state( $(this), 'unavailable' );
			}
		});	
	}
	
	function update_shop() 
	{
		get_view( 'shop' ).find('.shop_item').each( function() {
		
			if ( $(this).attr('item_id') ) 
			{
				var item = get_item_data( $(this).attr('item_id') );

				// Disable selection if:
				// 	1. Already got the item
				//	2. Has no slots free for that item
				//	3. The item is of a demigod class that isn't the users class
				
				if ( 	has_item( item ) 
						|| !slot_free( item.type ) 
						|| ( ($(this).attr('subtype')  == 'general' || $(this).attr('subtype') == 'assassin') && $(this).attr('subtype') != active.demigod.toon_class ) 
						|| ( active.demigod.toon_class != 'general' && $(this).attr('subtype').substr( 0, 5 ) == "idol_" )
					) {
					
					$(this).addClass('item_bought'); 
				} else {
					$(this).removeClass('item_bought');
				}
				
				$(this).skeletonTip( item.tooltip );
			}
		});
	}
	
	function update_skill_points() 
	{
		active.skill_points = calculate_skill_points();
		if ( active.skill_points < 0 ) {
			cap_abilities( active.skill_points*-1 );
			active.skill_points = 0;
		}
		update_view( 'skills_left', active.skill_points );
	}

	function update_spent() 
	{
		active.gold = 0;
		active.favor = 0;
		
		$.each( active.slots, function(slot_id, slot) {	
			var item = get_slot_item( slot_id );
			if ( !$.isEmptyObject( item ) ) { 
				if ( item.type != "favor" ) {
					active.gold += parseInt( item.cost );
				} else {
					active.favor += parseInt( item.cost );
				}
			}
		});

		update_view( 'gold', active.gold );
		update_view( 'favor', active.favor );
	}

	function update_effects()
	{	
		// Update Effect Triggers
		$('.effect_trigger').removeClass('effect_active');
		
		$.each( active.effects, function( effect_id, effect ) { 
			$('#effect_' + effect.id).addClass('effect_active');
		});
	}
	
	function update_ability_state( ability_obj, state ) 
	{
		ability_obj
			.removeClass('skill_available')
			.removeClass('skill_unavailable')
			.removeClass('skill_bought');
			
		switch ( state ) {
			case 'available':
				ability_obj.addClass('skill_available');
			break;
			case 'unavailable':
				ability_obj.addClass('skill_unavailable');
			break;
			case 'bought':
				ability_obj.addClass('skill_bought');
			break;
		}
	}
	
	function calculate_skill_points() {
		return active.demigod.level - parseInt( count_abilities() );
	}

	
	
	/*
	 * State Modification
	 */

	function load_build_profile() 
	{
		// Advanced Profile Loading Code will go here.

		var hash = location.hash;
		var split = hash.substr(1).split(":");
		
		if ( hash && split.length == 6 ) 
		{
			var DEMIGOD_ID 	= split[0];
			var LEVEL		= split[1];
			var ABILITIES 	= split[2];
			var ITEMS		= split[3];
			var EFFECTS		= split[4];
			var PAGE		= split[5];

			set_demigod( DEMIGOD_ID );
			set_demigod_attr( 'level', LEVEL );
			
			active.page = PAGE;
			
			if ( ABILITIES ) 
				decode_abilities( ABILITIES );
			
			if ( ITEMS ) 
				decode_items( ITEMS );
			
			if ( EFFECTS ) 
				decode_effects( EFFECTS );
		}
		
		else
		{
			// Set Default Demigod and Level
			set_demigod( get_view( 'demigod_select' ).val() );
			set_demigod_attr( 'level', 1 );
		}
	}
	
	function decode_abilities( abilities ) 
	{
		var tempId = 0;
		for ( var j=0; j< abilities.length; j++ ) 
		{
			var item = abilities.charAt( j );
			if ( reduce_skill( item, true ) >= 0 ) {
				tempId = reduce_skill( item, true ) * 25;
			} 
			else if ( encode_skill( item, true ) >= 0 ) 
			{
				tempId += encode_skill( item, true );
				active.abilities[ tempId ] = get_ability_data( tempId );
				tempId = 0;
			}
		}
	}
	
	function decode_items( items ) 
	{
		var item_id = 0;
		var slot = items.substr( 0, 2 );
		var rest = items.substr( 2 );
		
		for ( var j=0; j < rest.length; j++ ) 
		{
			var item = rest.charAt( j );
			if ( reduce_skill( item, true ) >= 0 ) {
				item_id = reduce_skill( item, true ) * 25;
			} 
			else if ( encode_skill( item, true ) >= 0 ) 
			{
				item_id += encode_skill( item, true );
				set_slot_item( slot, get_item_data( item_id ) );
				
				item_id = 0;
				slot = rest[j+1] + rest[j+2];
				j += 2;
			}
		}
	}
	
	function decode_effects( effects ) 
	{
		var tempId = 0;
		for ( var j=0; j < effects.length; j++ ) 
		{
			var item = effects.charAt( j );
			if ( reduce_skill( item, true ) >= 0 ) {
				tempId = reduce_skill( item, true ) * 25;
			} 
			else if ( encode_skill( item, true ) >= 0 ) 
			{
				tempId += encode_skill( item, true );
				active.effects[ tempId ] = tempId;
				tempId = 0;
			}
		}
	}
	
	/*
	 * reduce_state( state )
	 * Reduces the active profile into a bare minimum for transport to server
	 */
	 
	function reduce_state( state ) 
	{
		var rstate = {
			'demigod': active.demigod.id,
			'level': active.demigod.level,
			'items': [],
			'abilities': [],
			'effects': []
		};
		
		$.each( active.abilities, function(i,a) {
			rstate.abilities.push( a.id );
		});
		
		$.each( active.effects, function(i,a) {
			rstate.effects.push( a.id );
		});
		
		$.each( active.slots, function(i,a) {
			if ( !$.isEmptyObject( a.item ) ) {
				rstate.items.push( a.item.id );
			}
		});
		
		return $.toJSON( rstate );
	}
	
	/*
	 * update_hash()
	 * Updates the hash, encoding the current active state into a hash
	 */
	
	function update_hash() 
	{
		// If there is no Demigod, no sense storing state
		if ( $.isEmptyObject( active.demigod ) ) 
			return false;
			
		var page = active.page;
		var demigod = active.demigod.id;
		var level = active.demigod.level;
		
		var abilities = "";
		var items = "";
		var effects = "";
		
		$.each( active.abilities, function(i,a) {
			abilities += reduce_skill( a.id ) + encode_skill( a.id % 25 );
		});
		
		$.each( active.effects, function(i,a) {
			effects += reduce_skill( a.id ) + encode_skill( a.id % 25 );
		});
		
		$.each( active.slots, function(i,a) {
			if ( !$.isEmptyObject( a.item ) ) {
				items += i + reduce_skill( a.item.id ) + encode_skill( a.item.id % 25 );
			}
		});
		
		var hash = demigod + ":" + level + ":" + abilities + ":" + items + ":" + effects + ":" + page;

		location.hash = hash;
	}
	
	function encode_skill( id, reverse ) {
		var letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567-=_[].=+";
		return ( !reverse ) ? letters.charAt(id) : letters.indexOf(id);
	}

	function reduce_skill( id, reverse ) {
		var tempId = id;
		var letters = "abcdefghijklmnopqrstuvwxyz09";
		
		if( reverse === undefined ) tempId = Math.floor( id / 25 );

		return ( !reverse ) ? letters.charAt(tempId) : letters.indexOf(tempId);
	}
	
	

	/*
	 * External AJAX Requests
	 */

	function get_demigod_db() {
		syncronous_json('javascript/demigod.json', function( json ) { demigoddb = json; } );
	}

	function get_items_db() {
		syncronous_json('javascript/item.json', function( json ) { 
			itemsdb = json; 
			$.each( itemsdb, function(i,a) {
				
				if ( !$.isEmptyObject( a ) ) {
					if ( a.custom_slot ) { 
						itemsdb[ a.id ].type = a.custom_slot;
					}
				}
			});
		} );
	}

	function get_abilities_db() {
		syncronous_json('javascript/ability.json', function( json ) { abilitiesdb = json; } );
	}

	function get_tech_tree() 
	{	
		var html = "<div id='ability_tech_tree_container'>Loading Tech Tree...<br /><br /><center><img src='images/loading.gif' /></center></div>";
		update_view( 'tech_tree', html );
		
		$.ajax({
			type: "POST",
			data: "demigod_id=" + get_demigod_attr( 'id' ),
			url: "rpc/tech_tree_html.php",
			success: function( html ) { update_view( 'tech_tree', html ); refresh_ui(); }
		});
	}



	/*
	 * Stored Data Accessors
	 */

	function get_item_data( item_id ) {
		return itemsdb[ item_id ];
	}

	function get_ability_data( ability_id ) {
		return abilitiesdb[ ability_id ];
	}

	function get_demigod_data( demigod_id ) {
		return demigoddb[ demigod_id ];
	}


	
	/*
	 * Effects
	 */
	
	function get_effect( effect_id ) 
	{
		var effect = { 'id': effect_id };
		
		if ( !has_effect( effect ) ) {
			active.effects[ effect.id ] = effect;
		} else {
			remove_effect( effect );
		}
		refresh_ui();				
	}

	function has_effect( effect ) {
		if ( !$.isEmptyObject( active.effects[ effect.id ] ) ) {
			return active.effects[ effect.id ];
		} else {
			return false;
		}	
	}
	
	function remove_effect( effect ) {
		delete active.effects[ effect.id ];
	}
	
	
	
	
	/*
	 * Abilities
	 */
	 
	function get_ability( ability_id ) 
	{
		var ability = get_ability_data( ability_id );
		
		// If doesn't have skill, has skill points, and if required, the previous skill
		if (  !has_ability( ability ) && active.skill_points > 0 && check_ability_availability( ability ) ) 
		{
			active.abilities[ ability.id ] = ability;
			ensure_dependancies( ability );
			refresh_ui();
		}
		else if ( has_ability( ability ) ) {
			remove_ability( ability );
			refresh_ui();
		}
	}
	 
	function count_abilities() {
		var count = 0;
		$.each( active.abilities, function( ability_id, ability ) {
			count++;
		});
		return count;
	}
	 
	function remove_ability( ability ) {
		delete active.abilities[ ability.id ];
	} 

	function cap_abilities( number ) {
		
		// Remove 'number' abiltiies from the user
		// (For when user decreases level after assigning high abilities)
		
		$.each( active.abilities, function( ability_id, ability ) {
			if ( number == 0 ) {
				return false;
			} else {
				remove_ability( ability );
				number--;
			}
		});
	}
	 
	function has_ability( ability ) {
		if ( !$.isEmptyObject( active.abilities[ ability.id ] ) ) {
			return active.abilities[ ability.id ];
		} else {
			return false;
		}	
	}
	
	function ensure_dependancies( ability ) 
	{
		if ( !$.isEmptyObject( ability.dependancies ) ) {
			found = false;
			$.each( ability.dependancies, function( dependant_id, dependant ) {
				var dep = get_ability_data( dependant_id );
				
				// Add the dependency to the abilities list
				if ( !$.isEmptyObject( dep ) && !has_ability( dep ) ) {
					active.abilities[ dep.id ] = dep;
					ensure_dependancies( dep );
				}
			});
		}
	}

	function check_ability_availability( ability ) {

		// If ability is beyond the players level, return false

		if ( ability.available_level > parseInt( get_demigod_attr( 'level' ) ) ) {
			//console.log( "Ability " + ability.id + " level is too high" );
			return false;
		}
		
		// If ability requires dependancies the player doesn't have, return false
		if ( !active.shift_down && !$.isEmptyObject( ability.dependancies ) ) {
			found = false;
			$.each( ability.dependancies, function( dependant_id, dependant ) {
				var dep = get_ability_data( dependant_id );
				if ( !$.isEmptyObject( dep ) && !has_ability( dep ) ) {
					//console.log( "Ability " + ability.id + " doesn't have dependancy " + dep.id );
					found = true;
					return false;
				}
			});
			
			if ( found ) {
				return false;
			}
		}

		// Otherwise, ability is available!

		return true;
	}



	/*
	 * User Demigod
	 */

	function set_demigod( demigod_id ) 
	{
		active.demigod = get_demigod_data( demigod_id );
		set_demigod_attr( 'level', get_view( 'level_select' ).val() );

		// Reset Abilities as they cannot be the same
		active.skill_points = active.demigod.level;
		active.abilities = {};
		
		// Whenever the Demigod changes, the type needs to be updated
		active.demigod.toon_class = ( active.demigod.type == 'General' ) ? 'general' : 'assassin';
		
		$('#items').removeClass().addClass( "ui_" + active.demigod.toon_class );
		
		if ( active.demigod.toon_class == "assassin" ) {
			$('#slot_g1, #slot_g2, #slot_g3').hide();
		} else {
			$('#slot_g1, #slot_g2, #slot_g3').show();
		}
		
		// Whenever the Demigod changes, the new techtree will need to be loaded.
		get_tech_tree();

		get_view('portrait').attr({src: "images/demigods/" + active.demigod.name.toLowerCase().replace(/ /g, "_") + ".png"});

		refresh_ui();
	}

	function set_demigod_attr( attribute, value ) {
		active.demigod[ attribute ] = value;
	}

	function get_demigod_attr( attribute ) {
		return active.demigod[ attribute ];
	}



	/*
	 * Items and Slots
	 */

	function get_slot_item( slot_id ) {
		return active.slots[ slot_id ].item;
	}

	function set_slot_item( slot_id, item ) {
		active.slots[ slot_id ].item = item;
	}

	function slot_free( type ) 
	{
		var found = false;

		// Return slot_id if found, otherwise, false
		$.each( active.slots, function(slot_id, slot) {
			if ( slot.type == type && $.isEmptyObject( slot.item ) ) { 
				found = slot_id;
				return false;
			}
		});
		return found;
	}

	function has_item( item ) 
	{
		var found = false;
		$.each( active.slots, function(slot_id, slot) {
			if ( !$.isEmptyObject( slot.item ) ) { 
				if ( slot.item.id == item.id ) {
					found = true;
					return false;
				}
			}
		});
		return found;
	}



	/*
	 * Buying and Selling
	 */
	 
	function sell( slot_id )
	{
		var item = get_slot_item( slot_id );
		if ( !$.isEmptyObject( item ) ) 
		{ 
			set_slot_item( slot_id, {} );
			refresh_ui();
		}
	}

	function purchase( item_id ) 
	{
		var item = get_item_data( item_id );
		
		var free_slot = slot_free( item.type );
		
		// Ensure the user doesn't already own the item, 
		// and that there is a free spot
		if ( !has_item( item ) && free_slot && ( (item.item_type != 'general' && item.item_type != 'assassin') || item.item_type == active.demigod.toon_class ) )
		{
			set_slot_item( free_slot, item );
			set_slot_item( free_slot, item );
			refresh_ui();
		}
	}



	/* 
	 * On Document Load 
	 */

	$(document).ready(function() {
		
		// Load Page
		$("#page_loading").show();
		setup_ui();
		load_build_profile();
		refresh_ui();

		// Selector Bindings

		dg_select = get_view( 'demigod_select' );
		dg_select.bind('change', function() {
			set_demigod( $(this).val() );
		});

		lvl_select = get_view( 'level_select' );
		lvl_select.bind('change', function() {
			set_demigod_attr( 'level', $(this).val() );
			refresh_ui();
		});
		
		// Shop Bindings
		 
		$('.item_slot').live('click', function() {
			sell( $(this).attr('slot') );
		});
		 
		$('.shop_item').live('hover', function() {
			$(this).toggleClass('itemHover');
		});
		
		$('.shop_item').live('click', function() {
			purchase( $(this).attr('item_id') );
		});
		
		// Ability Bindings 
		
		$('.ability_tech').live('click', function() {
			get_ability(  $(this).attr('skill_id') );
		});
		
		get_view( 'reset_skills' ).click(function() {
			active.abilities = {};
			refresh_ui();
			return false;
		});
		
		$(window).bind('keydown', function(e) {
			if (e.shiftKey && !active.shift_down) {
				active.shift_down = true;
				refresh_ui();
			}
		}).bind('keyup', function(e) {
			if (!e.shiftKey && active.shift_down) {
				active.shift_down = false;
				refresh_ui();
			}
		});
		
		// Effect Bindings
		
		$('.effect_trigger').live('click', function() {
			get_effect(  $(this).attr('effect_id') );
		});
		
		// Navigation Bindings
		 
		$('.page_type').click(function() {
			load_page( $(this).attr('page') );
		});
		
		$('.store_type').click(function() {
			load_store( $(this).attr('store') );
		});
		
		$('#open_calculator').click(function() {
			$('#character_statistics').toggle();
			load_statistics();
		});
		
		// Stylistic Bindings

		$('.page_type, .store_type').hover(function() {
			$(this).toggleClass('itemHover');
		});
		
		// Load Page
		
		load_page( active.page );
	});
})();