public void PrepareData(TextFxAnimationManager anim_manager,
								ref LetterSetup[] letters,
		                        LetterAnimation animation_ref,
		                        int action_idx,
		                        ANIMATION_DATA_TYPE what_to_update,
		                        int num_letters,
		                        int num_white_space_chars_to_include,
		                        int num_words,
		                        int num_lines,
		                        LetterAction prev_action,
		                        AnimatePerOptions animate_per,
		                        ActionColorProgression defaultTextColour,
		                        bool prev_action_end_state = true)
		{
			// Set progression reference datas 
			m_start_colour.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.COLOUR, true);
			m_start_euler_rotation.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.LOCAL_ROTATION, true);
			m_start_pos.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.POSITION, true);
			m_start_scale.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.LOCAL_SCALE, true);
			m_global_start_euler_rotation.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.GLOBAL_ROTATION, true);
			m_global_start_scale.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.GLOBAL_SCALE, true);
			m_end_colour.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.COLOUR, false);
			m_end_euler_rotation.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.LOCAL_ROTATION, false);
			m_end_pos.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.POSITION, false);
			m_end_scale.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.LOCAL_SCALE, false);
			m_global_end_euler_rotation.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.GLOBAL_ROTATION, false);
			m_global_end_scale.SetReferenceData(action_idx, ANIMATION_DATA_TYPE.GLOBAL_SCALE, false);


			// Prepare Data

			if(what_to_update == ANIMATION_DATA_TYPE.DURATION || what_to_update == ANIMATION_DATA_TYPE.ALL)
				m_duration_progression.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, m_duration_progression.AnimatePer, m_duration_progression.OverrideAnimatePerOption));


			if((what_to_update == ANIMATION_DATA_TYPE.AUDIO_EFFECTS || what_to_update == ANIMATION_DATA_TYPE.ALL) && m_audio_effects != null)
			{
				foreach(AudioEffectSetup effect_setup in m_audio_effects)
				{
					effect_setup.m_delay.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, effect_setup.m_delay.AnimatePer, effect_setup.m_delay.OverrideAnimatePerOption));
					effect_setup.m_offset_time.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, effect_setup.m_offset_time.AnimatePer, effect_setup.m_offset_time.OverrideAnimatePerOption));
					effect_setup.m_volume.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, effect_setup.m_volume.AnimatePer, effect_setup.m_volume.OverrideAnimatePerOption));
					effect_setup.m_pitch.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, effect_setup.m_pitch.AnimatePer, effect_setup.m_pitch.OverrideAnimatePerOption));
				}
			}

			if((what_to_update == ANIMATION_DATA_TYPE.PARTICLE_EFFECTS || what_to_update == ANIMATION_DATA_TYPE.ALL) && m_particle_effects != null)
			{
				foreach(ParticleEffectSetup effect_setup in m_particle_effects)
				{
					effect_setup.m_position_offset.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, effect_setup.m_position_offset.AnimatePer, effect_setup.m_position_offset.OverrideAnimatePerOption), null);
					effect_setup.m_rotation_offset.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, effect_setup.m_rotation_offset.AnimatePer, effect_setup.m_rotation_offset.OverrideAnimatePerOption), null);
					effect_setup.m_delay.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, effect_setup.m_delay.AnimatePer, effect_setup.m_delay.OverrideAnimatePerOption));
					effect_setup.m_duration.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, effect_setup.m_duration.AnimatePer, effect_setup.m_duration.OverrideAnimatePerOption));
				}
			}
			
			if(m_action_type == ACTION_TYPE.BREAK)
			{
				if(prev_action != null)
				{
					m_start_colour.SetValueReference(prev_action_end_state ? prev_action.m_end_colour : prev_action.m_start_colour);
					m_start_euler_rotation.SetValueReference( prev_action_end_state ? prev_action.m_end_euler_rotation : prev_action.m_start_euler_rotation );
					m_start_pos.SetValueReference( prev_action_end_state ? prev_action.m_end_pos : prev_action.m_start_pos );
					m_start_scale.SetValueReference( prev_action_end_state ? prev_action.m_end_scale : prev_action.m_start_scale );
					m_global_start_euler_rotation.SetValueReference( prev_action_end_state ? prev_action.m_global_end_euler_rotation : prev_action.m_global_start_euler_rotation );
					m_global_start_scale.SetValueReference( prev_action_end_state ? prev_action.m_global_end_scale : prev_action.m_global_start_scale );
				}

				m_end_colour.SetValueReference(m_start_colour);
				m_end_euler_rotation.SetValueReference(m_start_euler_rotation );
				m_end_pos.SetValueReference( prev_action.m_start_pos );
				m_end_scale.SetValueReference( prev_action.m_start_scale );
				m_global_end_euler_rotation.SetValueReference(prev_action.m_global_start_euler_rotation );
				m_global_end_scale.SetValueReference( prev_action.m_global_start_scale );

				return;
			}

			if (animation_ref.m_letters_to_animate_option != LETTERS_TO_ANIMATE.ALL_LETTERS || (((ValueProgression)m_delay_progression.Progression) != ValueProgression.Eased && ((ValueProgression)m_delay_progression.Progression) != ValueProgression.EasedCustom))
				m_delay_with_white_space_influence = false;


			if(what_to_update == ANIMATION_DATA_TYPE.DELAY || what_to_update == ANIMATION_DATA_TYPE.ALL)
				m_delay_progression.CalculateProgressions(GetProgressionTotal(num_letters + (m_delay_with_white_space_influence ? num_white_space_chars_to_include : 0), num_words, num_lines, animate_per, m_delay_progression.AnimatePer, m_delay_progression.OverrideAnimatePerOption));
			

			if(what_to_update == ANIMATION_DATA_TYPE.COLOUR || what_to_update == ANIMATION_DATA_TYPE.ALL)
			{
				if(m_offset_from_last && prev_action != null)
				{
					m_start_colour.SetValueReference(prev_action_end_state ? prev_action.m_end_colour : prev_action.m_start_colour );
				}
				else
				{
					m_start_colour.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, m_start_colour.AnimatePer, m_start_colour.OverrideAnimatePerOption), 
					                                     prev_action != null ? prev_action.m_end_colour : defaultTextColour,
					                                     prev_action == null || m_colour_transition_active);
				}

				m_end_colour.CalculateProgressions(GetProgressionTotal(num_letters, num_words, num_lines, animate_per, m_end_colour.AnimatePer, m_end_colour.OverrideAnimatePerOption),
				                                   m_start_colour,
				                                   prev_action == null || m_colour_transition_active);
			}
			
			
			if(m_offset_from_last && prev_action != null)
			{
				if(what_to_update == ANIMATION_DATA_TYPE.POSITION || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_start_pos.SetValueReference( prev_action_end_state ? prev_action.m_end_pos : prev_action.m_start_pos );

				if(what_to_update == ANIMATION_DATA_TYPE.LOCAL_ROTATION || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_start_euler_rotation.SetValueReference( prev_action_end_state ? prev_action.m_end_euler_rotation : prev_action.m_start_euler_rotation );

				if(what_to_update == ANIMATION_DATA_TYPE.LOCAL_SCALE || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_start_scale.SetValueReference( prev_action_end_state ? prev_action.m_end_scale : prev_action.m_start_scale );

				if(what_to_update == ANIMATION_DATA_TYPE.GLOBAL_ROTATION || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_global_start_euler_rotation.SetValueReference( prev_action_end_state ? prev_action.m_global_end_euler_rotation : prev_action.m_global_start_euler_rotation );

				if(what_to_update == ANIMATION_DATA_TYPE.GLOBAL_SCALE || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_global_start_scale.SetValueReference( prev_action_end_state ? prev_action.m_global_end_scale : prev_action.m_global_start_scale );
			}
			else
			{
				float[] start_pos_curve_letter_progressions = null;
				if(	(	what_to_update == ANIMATION_DATA_TYPE.POSITION ||
					    what_to_update == ANIMATION_DATA_TYPE.LOCAL_ROTATION ||
				     	what_to_update == ANIMATION_DATA_TYPE.GLOBAL_ROTATION ||
				     	what_to_update == ANIMATION_DATA_TYPE.ALL
				    )
					&& m_start_pos.Progression == ActionPositionVector3Progression.CURVE_OPTION_INDEX)
				{
					// Pre calculate letter progression values based on letter spacing
					start_pos_curve_letter_progressions = m_start_pos.BezierCurve.GetLetterProgressions(anim_manager, ref letters, m_letter_anchor_start);
				}

				if(what_to_update == ANIMATION_DATA_TYPE.POSITION || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_start_pos.CalculatePositionProgressions(	anim_manager,
					                                          	animation_ref,
					                                          	ref start_pos_curve_letter_progressions,
					                                          	letters,
					                                          	GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_start_pos.AnimatePer, m_start_pos.OverrideAnimatePerOption),
																prev_action != null ? prev_action.m_end_pos : null,
					                                          	prev_action == null || m_position_transition_active);

				if(what_to_update == ANIMATION_DATA_TYPE.LOCAL_ROTATION || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_start_euler_rotation.CalculateRotationProgressions(ref start_pos_curve_letter_progressions, GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_start_euler_rotation.AnimatePer, m_start_euler_rotation.OverrideAnimatePerOption),
																			prev_action != null ? prev_action.m_end_euler_rotation : null,
			                                                     			m_start_pos.Progression == ActionPositionVector3Progression.CURVE_OPTION_INDEX ? m_start_pos.BezierCurve : null,
					                                                     	prev_action == null || m_local_rotation_transition_active);

				if(what_to_update == ANIMATION_DATA_TYPE.LOCAL_SCALE || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_start_scale.CalculateProgressions(GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_start_scale.AnimatePer, m_start_scale.OverrideAnimatePerOption),
														prev_action != null ? prev_action.m_end_scale : null,
					                                    prev_action == null || m_local_scale_transition_active);

				if(what_to_update == ANIMATION_DATA_TYPE.GLOBAL_ROTATION || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_global_start_euler_rotation.CalculateRotationProgressions(ref start_pos_curve_letter_progressions, GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_global_start_euler_rotation.AnimatePer, m_global_start_euler_rotation.OverrideAnimatePerOption),
					                                                            prev_action != null ? prev_action.m_global_end_euler_rotation : null,
					                                                            null,
					                                                            prev_action == null || m_global_rotation_transition_active);

				if(what_to_update == ANIMATION_DATA_TYPE.GLOBAL_SCALE || what_to_update == ANIMATION_DATA_TYPE.ALL)
					m_global_start_scale.CalculateProgressions(	GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_global_start_scale.AnimatePer, m_global_start_scale.OverrideAnimatePerOption),
				                                           		prev_action != null ? prev_action.m_global_end_scale : null,
					                                           	prev_action == null || m_global_scale_transition_active);
			}
			
			float[] end_pos_curve_letter_progressions = null;
			if(	(	what_to_update == ANIMATION_DATA_TYPE.POSITION ||
			     	what_to_update == ANIMATION_DATA_TYPE.LOCAL_ROTATION ||
			     	what_to_update == ANIMATION_DATA_TYPE.GLOBAL_ROTATION ||
			     	what_to_update == ANIMATION_DATA_TYPE.ALL
			    )
			   	&& m_end_pos.Progression == ActionPositionVector3Progression.CURVE_OPTION_INDEX)
			{
				// Pre calculate letter progression values based on letter spacing
				end_pos_curve_letter_progressions = m_end_pos.BezierCurve.GetLetterProgressions(anim_manager, ref letters, m_letter_anchor_end);
			}

			if(what_to_update == ANIMATION_DATA_TYPE.POSITION || what_to_update == ANIMATION_DATA_TYPE.ALL)
				m_end_pos.CalculatePositionProgressions(anim_manager,
				                                        animation_ref,
				                                        ref end_pos_curve_letter_progressions,
				                                        letters,
				                                        GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_end_pos.AnimatePer, m_end_pos.OverrideAnimatePerOption),
				                                        m_start_pos,
				                                        prev_action == null || m_position_transition_active);

			if(what_to_update == ANIMATION_DATA_TYPE.LOCAL_ROTATION || what_to_update == ANIMATION_DATA_TYPE.ALL)
				m_end_euler_rotation.CalculateRotationProgressions(ref end_pos_curve_letter_progressions, GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_end_euler_rotation.AnimatePer, m_end_euler_rotation.OverrideAnimatePerOption),
				                                                   m_start_euler_rotation,
				                                                   m_end_pos.Progression == ActionPositionVector3Progression.CURVE_OPTION_INDEX ? m_end_pos.BezierCurve : null,
				                                                   prev_action == null || m_local_rotation_transition_active);

			if(what_to_update == ANIMATION_DATA_TYPE.LOCAL_SCALE || what_to_update == ANIMATION_DATA_TYPE.ALL)
				m_end_scale.CalculateProgressions(GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_end_scale.AnimatePer, m_end_scale.OverrideAnimatePerOption),
				                                  m_start_scale,
				                                  prev_action == null || m_local_scale_transition_active);

			if(what_to_update == ANIMATION_DATA_TYPE.GLOBAL_ROTATION || what_to_update == ANIMATION_DATA_TYPE.ALL)
				m_global_end_euler_rotation.CalculateRotationProgressions(ref end_pos_curve_letter_progressions, GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_global_end_euler_rotation.AnimatePer, m_global_end_euler_rotation.OverrideAnimatePerOption),
				                                                          m_global_start_euler_rotation,
				                                                          null,
				                                                          prev_action == null || m_global_rotation_transition_active);

			if(what_to_update == ANIMATION_DATA_TYPE.GLOBAL_SCALE || what_to_update == ANIMATION_DATA_TYPE.ALL)
				m_global_end_scale.CalculateProgressions(GetProgressionTotal(num_letters + num_white_space_chars_to_include, num_words, num_lines, animate_per, m_global_end_scale.AnimatePer, m_global_end_scale.OverrideAnimatePerOption),
				                                         m_global_start_scale,
				                                         prev_action == null || m_global_scale_transition_active);

			if(what_to_update == ANIMATION_DATA_TYPE.POSITION
			   || what_to_update == ANIMATION_DATA_TYPE.POSITION
			   || what_to_update == ANIMATION_DATA_TYPE.LETTER_ANCHOR
			   || what_to_update == ANIMATION_DATA_TYPE.ALL)
				CalculateLetterAnchorOffset();
		}
		public void SoftResetStarts(LetterAction prev_action, AnimationProgressionVariables progression_variables, AnimatePerOptions animate_per)
		{
			if(!m_offset_from_last && m_start_colour.UniqueRandom)
			{
				m_start_colour.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_end_colour.Values : null);
			}
			
			if(!m_offset_from_last)
			{
				if(m_start_pos.UniqueRandom)
				{
					m_start_pos.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_end_pos.Values : null);
				}
				if(m_start_euler_rotation.UniqueRandom)
				{
					m_start_euler_rotation.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_end_euler_rotation.Values : null);
				}
				if(m_start_scale.UniqueRandom)
				{
					m_start_scale.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_end_scale.Values : null);
				}
				if(m_global_start_euler_rotation.UniqueRandom)
				{
					m_global_start_euler_rotation.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_global_end_euler_rotation.Values : null);
				}
				if(m_global_start_scale.UniqueRandom)
				{
					m_global_start_scale.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_global_end_scale.Values : null);
				}
			}
		}
		public LetterAction ContinueActionFromThis()
		{
			LetterAction letter_action = new LetterAction();
			
			// Default to offset from previous and not be folded in editor
			letter_action.m_offset_from_last = true;
			letter_action.m_editor_folded = true;
			
			letter_action.m_position_axis_ease_data = m_position_axis_ease_data.Clone();
			letter_action.m_rotation_axis_ease_data = m_rotation_axis_ease_data.Clone();
			letter_action.m_scale_axis_ease_data = m_scale_axis_ease_data.Clone();
			
			letter_action.m_start_colour = m_end_colour.Clone();
			letter_action.m_end_colour = m_end_colour.Clone();
			
			letter_action.m_start_pos = m_end_pos.CloneThis();
			letter_action.m_end_pos = m_end_pos.CloneThis();
			
			letter_action.m_start_euler_rotation = m_end_euler_rotation.Clone();
			letter_action.m_end_euler_rotation = m_end_euler_rotation.Clone();
			
			letter_action.m_start_scale = m_end_scale.Clone();
			letter_action.m_end_scale = m_end_scale.Clone();

			letter_action.m_global_start_euler_rotation = m_global_end_euler_rotation.Clone();
			letter_action.m_global_end_euler_rotation = m_global_end_euler_rotation.Clone();
			
			letter_action.m_global_start_scale = m_global_end_scale.Clone();
			letter_action.m_global_end_scale = m_global_end_scale.Clone();
			
			letter_action.m_delay_progression = new ActionFloatProgression(0);
			letter_action.m_duration_progression = new ActionFloatProgression(1);
			
			letter_action.m_letter_anchor_start = m_letter_anchor_2_way ? m_letter_anchor_end : m_letter_anchor_start;
			
			letter_action.m_ease_type = m_ease_type;
			
			return letter_action;
		}
		void DrawGUIAnimationSettings(TextFxAnimationManager.PRESET_ANIMATION_SECTION section, string folder_name, ref float gui_y_offset, ref bool foldout, ref int selected_index, ref TextFxAnimationManager.PresetAnimationSection preset_anim_section, string[] anim_titles)
		{
			if(selected_index > 0)
				foldout = EditorGUI.Foldout (new Rect (20, gui_y_offset, 80, 20), foldout, TextFxAnimationManager.m_animation_section_names[(int) section], true, FoldOutHeaderGUIStyle);
			else
				EditorGUI.LabelField(new Rect (20, gui_y_offset, 80, 20), TextFxAnimationManager.m_animation_section_names[(int) section], HeaderGUIStyle);

			bool gui_changed = GUI.changed;

			// Draw Section loop options
			if(section == TextFxAnimationManager.PRESET_ANIMATION_SECTION.MAIN && selected_index > 0)
			{
				if(GUI.Button (new Rect (310, gui_y_offset - 7, 40, 40), preset_anim_section.m_repeat ? m_repeat_on_button_texture : m_repeat_off_button_texture, ButtonImageOnlyGUIStyle))
				{
					preset_anim_section.m_repeat = !preset_anim_section.m_repeat;
				}

				if(!gui_changed && GUI.changed)
				{
					// Update section loop settings
					if(!preset_anim_section.m_repeat)
					{
						// Remove section repeat loop
						m_animation_manager.m_master_animations[0].RemoveLoop(GetSectionRepeatLoopIndex(section));
					}
					else
					{
						// Add in a repeat loop
						ActionLoopCycle new_loop = new ActionLoopCycle();
						new_loop.m_start_action_idx = preset_anim_section.m_start_action;
						new_loop.m_end_action_idx = preset_anim_section.m_start_action + preset_anim_section.m_num_actions;
						new_loop.m_number_of_loops = preset_anim_section.m_repeat_count;

						m_animation_manager.m_master_animations[0].InsertLoop(GetSectionRepeatLoopIndex(section), new_loop);
					}
				}

				if(preset_anim_section.m_repeat)
				{
					gui_changed = GUI.changed;

					// display repeat num field
					preset_anim_section.m_repeat_count = Mathf.Max(EditorGUI.IntField(new Rect(355, gui_y_offset + 2, 30, LINE_HEIGHT), preset_anim_section.m_repeat_count), 0);
					
					if(preset_anim_section.m_repeat_count == 0)
					{
						GUI.DrawTexture(new Rect(390, gui_y_offset - 8, 40, 40), m_infinity_texture);
					}

					if(!gui_changed && GUI.changed)
					{
						// Update loop with current repeat count
						ActionLoopCycle repeat_loop = m_animation_manager.m_master_animations[0].GetLoop(GetSectionRepeatLoopIndex(section));
						repeat_loop.m_number_of_loops = preset_anim_section.m_repeat_count;
					}
				}
			}
			

			gui_changed = GUI.changed;

			selected_index = EditorGUI.Popup (new Rect (120, gui_y_offset, 180, 20), selected_index, anim_titles, PopupHeaderGUIStyle);
			
			if(!gui_changed && GUI.changed)
			{
				if(m_animation_manager.WipeFullEditorData(user_confirm: true))
				{
					// Handle removing any existing section anim
					if(preset_anim_section.m_num_actions > 0
					   && m_animation_manager.m_master_animations != null
					   && m_animation_manager.m_master_animations.Count > 0
					   && m_animation_manager.m_master_animations[0].NumActions >= preset_anim_section.m_num_actions + 1)
					{
						m_animation_manager.m_master_animations[0].RemoveActions(preset_anim_section.m_start_action, preset_anim_section.m_num_actions + 1);

						m_animation_manager.m_master_animations[0].RemoveLoops(preset_anim_section.m_start_loop, preset_anim_section.m_num_loops);
					}
					
					// Animation selection changed. Update animation to reflect this
					if(selected_index > 0)
					{
						preset_anim_section.m_repeat = false;
						preset_anim_section.m_repeat_count = 0;

						string path = "Assets/TextFx/AnimationConfigs/" + folder_name + "/" + anim_titles[selected_index] + ".txt";
						path = path.Replace("\n", "");
						path = path.Replace("\r", "");
						
						TextAsset animation_config_data = AssetDatabase.LoadAssetAtPath(path, typeof(TextAsset)) as TextAsset;
						
//						Debug.Log("Importing from : " + path + ", animation_config_data : " + (animation_config_data != null));
						
						if(animation_config_data != null)
						{
							preset_anim_section.m_active = true;

							m_animation_manager.ImportData(animation_config_data.text, preset_anim_section, section, true);

							// Add in an Exit Pause action after the end of this section
							LetterAction exit_pause_action = new LetterAction();
							exit_pause_action.m_action_type = ACTION_TYPE.BREAK;

							// Initialise delay duration based on existing settings
							exit_pause_action.m_duration_progression.SetConstant(preset_anim_section.m_exit_pause ? preset_anim_section.m_exit_pause_duration : INACTIVE_EXIT_PAUSE_DURATION);

							m_animation_manager.m_master_animations[0].InsertAction(preset_anim_section.ExitPauseIndex, exit_pause_action);

							m_animation_manager.PrepareAnimationData (ANIMATION_DATA_TYPE.DURATION);
						}
					}
					else
					{
						preset_anim_section.m_active = false;
						preset_anim_section.m_num_actions = 0;
						preset_anim_section.m_num_loops = 0;
					}
					
					UpdatePresetAnimSectionActionIndexes();

					// Update global loop settings if active
					if(m_animation_manager.m_repeat_all_sections)
					{
						ActionLoopCycle global_loop = m_animation_manager.m_master_animations[0].GetLoop(m_animation_manager.GlobalRepeatLoopStartIndex);

						if(global_loop == null)
						{
							// Global loop was removed during section rearranging. Re-add one in.
							global_loop = new ActionLoopCycle();
							global_loop.m_number_of_loops = m_animation_manager.m_repeat_all_sections_count;
							m_animation_manager.m_master_animations[0].InsertLoop(m_animation_manager.GlobalRepeatLoopStartIndex, global_loop, true);
						}

						global_loop.m_start_action_idx = 0;
						global_loop.m_end_action_idx = m_animation_manager.m_preset_outro.m_start_action + (m_animation_manager.m_preset_outro.m_active ? m_animation_manager.m_preset_outro.m_num_actions : -1);
					}
				}
				else
				{
					// Set selected anim index back to NONE
					selected_index = 0;
				}
			}
			
			gui_y_offset += 35;
			
			if(foldout && selected_index > 0)
			{
				if(preset_anim_section.m_preset_effect_settings == null || preset_anim_section.m_preset_effect_settings.Count == 0)
				{
					return;
				}

				bool setting_changed = false;

				float gui_x_offset = 60;

				GUI.Label(new Rect(gui_x_offset - 5, gui_y_offset, 120, LINE_HEIGHT), "Section Settings", EditorStyles.boldLabel);

				if(GUI.Button(new Rect(gui_x_offset + 150, gui_y_offset, 100, LINE_HEIGHT), "Play Section"))
					setting_changed = true;

				gui_y_offset += 30;

				foreach(PresetEffectSetting effect_setting in preset_anim_section.m_preset_effect_settings)
				{
					if(effect_setting.DrawGUISetting(m_animation_manager, gui_x_offset, ref gui_y_offset, GUI.changed, preset_anim_section.m_start_action, preset_anim_section.m_start_loop))
						setting_changed = true;
				}

				// Display Exit Pause setting
				gui_changed = GUI.changed;
				preset_anim_section.m_exit_pause = EditorGUI.Toggle(new Rect(gui_x_offset, gui_y_offset, 200, LINE_HEIGHT), "Exit Delay", preset_anim_section.m_exit_pause);
				gui_y_offset += LINE_HEIGHT;

				if(!gui_changed && GUI.changed)
				{
					LetterAction exitPauseAction = m_animation_manager.m_master_animations[0].GetAction(preset_anim_section.ExitPauseIndex);

					exitPauseAction.m_duration_progression.SetConstant(preset_anim_section.m_exit_pause ? preset_anim_section.m_exit_pause_duration : INACTIVE_EXIT_PAUSE_DURATION);

					m_animation_manager.PrepareAnimationData(ANIMATION_DATA_TYPE.DURATION);

					UpdatePresetAnimSectionActionIndexes();
				}

				if(preset_anim_section.m_exit_pause)
				{
					LetterAction exit_pause_action = m_animation_manager.m_master_animations[0].GetAction(preset_anim_section.ExitPauseIndex);

					// Force to be Constant progression type
					if(exit_pause_action.m_duration_progression.Progression != (int) ValueProgression.Constant)
						exit_pause_action.m_duration_progression.SetConstant(exit_pause_action.m_duration_progression.ValueFrom);

					gui_changed = GUI.changed;

					float exit_pause_duration = Mathf.Max(EditorGUI.FloatField(new Rect(120, gui_y_offset, 200, LINE_HEIGHT), "Duration", exit_pause_action.m_duration_progression.ValueFrom), 0);
					gui_y_offset += LINE_HEIGHT;

					if(!gui_changed && GUI.changed)
					{
						exit_pause_action.m_duration_progression.SetConstant(exit_pause_duration);

						m_animation_manager.PrepareAnimationData(ANIMATION_DATA_TYPE.DURATION);

						setting_changed = true;
					}
				}


				if(setting_changed)
				{
					PlayEditorAnimation(preset_anim_section.m_start_action);
				}
			}

			gui_y_offset += LINE_HEIGHT;
		}
		public void SoftReset(LetterAction prev_action, AnimationProgressionVariables progression_variables, AnimatePerOptions animate_per, bool first_action = false)
		{
			if(!m_offset_from_last && !first_action)
			{
				if(m_start_colour.UniqueRandom)
				{
					m_start_colour.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_end_colour.Values : null);
				}
				if(m_start_pos.UniqueRandom)
				{
					m_start_pos.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_end_pos.Values : null);
				}
				if(m_start_euler_rotation.UniqueRandom)
				{
					m_start_euler_rotation.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_end_euler_rotation.Values : null);
				}
				if(m_global_start_euler_rotation.UniqueRandom)
				{
					m_global_start_euler_rotation.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_global_end_euler_rotation.Values : null);
				}
				if(m_start_scale.UniqueRandom)
				{
					m_start_scale.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_end_scale.Values : null);
				}
				if(m_global_start_scale.UniqueRandom)
				{
					m_global_start_scale.CalculateUniqueRandom(progression_variables, animate_per, prev_action != null ? prev_action.m_global_end_scale.Values : null);
				}
			}
			
			// End State Unique Randoms
			if(m_end_colour.UniqueRandom)
			{
				m_end_colour.CalculateUniqueRandom(progression_variables, animate_per, m_start_colour.Values);
			}
			if(m_end_pos.UniqueRandom)
			{
				m_end_pos.CalculateUniqueRandom(progression_variables, animate_per, m_start_pos.Values);
			}
			if(m_end_euler_rotation.UniqueRandom)
			{
				m_end_euler_rotation.CalculateUniqueRandom(progression_variables, animate_per, m_start_euler_rotation.Values);
			}
			if(m_end_scale.UniqueRandom)
			{
				m_end_scale.CalculateUniqueRandom(progression_variables, animate_per, m_start_scale.Values);
			}
			if(m_global_end_euler_rotation.UniqueRandom)
			{
				m_global_end_euler_rotation.CalculateUniqueRandom(progression_variables, animate_per, m_global_start_euler_rotation.Values);
			}
			if(m_global_end_scale.UniqueRandom)
			{
				m_global_end_scale.CalculateUniqueRandom(progression_variables, animate_per, m_global_start_scale.Values);
			}
			
			
			// Timing unique randoms
			if(m_delay_progression.UniqueRandom)
			{
				m_delay_progression.CalculateUniqueRandom(progression_variables, animate_per);
			}
			if(m_duration_progression.UniqueRandom)
			{
				m_duration_progression.CalculateUniqueRandom(progression_variables, animate_per);
			}
			
			if(m_audio_effects != null)
			{
				foreach(AudioEffectSetup effect_setup in m_audio_effects)
				{
					if(effect_setup.m_delay.UniqueRandom)
						effect_setup.m_delay.CalculateUniqueRandom(progression_variables, animate_per);
					if(effect_setup.m_offset_time.UniqueRandom)
						effect_setup.m_offset_time.CalculateUniqueRandom(progression_variables, animate_per);
					if(effect_setup.m_volume.UniqueRandom)
						effect_setup.m_volume.CalculateUniqueRandom(progression_variables, animate_per);
					if(effect_setup.m_pitch.UniqueRandom)
						effect_setup.m_pitch.CalculateUniqueRandom(progression_variables, animate_per);
				}
			}
			
			if(m_particle_effects != null)
			{
				foreach(ParticleEffectSetup effect_setup in m_particle_effects)
				{
					if(effect_setup.m_position_offset.UniqueRandom)
						effect_setup.m_position_offset.CalculateUniqueRandom(progression_variables, animate_per, null);
					if(effect_setup.m_rotation_offset.UniqueRandom)
						effect_setup.m_rotation_offset.CalculateUniqueRandom(progression_variables, animate_per, null);
					if(effect_setup.m_delay.UniqueRandom)
						effect_setup.m_delay.CalculateUniqueRandom(progression_variables, animate_per);
					if(effect_setup.m_duration.UniqueRandom)
						effect_setup.m_duration.CalculateUniqueRandom(progression_variables, animate_per);
				}
			}
		}
		public void ImportData(Boomlagoon.JSON.JSONObject json_data, string assetNameSuffix = "")
		{
			
			m_letters_to_animate = json_data["m_letters_to_animate"].Array.JSONtoListInt();
			m_letters_to_animate_custom_idx = (int) json_data["m_letters_to_animate_custom_idx"].Number;
			m_letters_to_animate_option = (LETTERS_TO_ANIMATE) (int) json_data["m_letters_to_animate_option"].Number;
			
			m_letter_actions = new List<LetterAction>();
			LetterAction letter_action;
			foreach(Boomlagoon.JSON.JSONValue action_data in json_data["ACTIONS_DATA"].Array)
			{
				letter_action = new LetterAction();
				letter_action.ImportData(action_data.Obj, assetNameSuffix);
				m_letter_actions.Add(letter_action);
			}

			m_loop_cycles = new List<ActionLoopCycle>();
			if(json_data.ContainsKey("LOOPS_DATA"))
			{
				ActionLoopCycle loop_cycle;
				
				foreach(Boomlagoon.JSON.JSONValue loop_data in json_data["LOOPS_DATA"].Array)
				{
					loop_cycle = new ActionLoopCycle();
					loop_cycle.ImportData(loop_data.Obj);
					
					// Check for invalid loops
					if(loop_cycle.m_start_action_idx < m_letter_actions.Count && loop_cycle.m_end_action_idx < m_letter_actions.Count)
					{
						m_loop_cycles.Add(loop_cycle);
					}
					
				}
			}
		}
		public void ImportPresetSectionData(Boomlagoon.JSON.JSONObject json_data, LetterSetup[] letters, int action_insert_index, int loop_insert_index, ref int num_actions_added, ref int num_loops_added, string assetNameSuffix = "")
		{
			if(m_letter_actions == null)
				m_letter_actions = new List<LetterAction>();

			float timing_scale = -1;

			if(m_letters_to_animate == null || m_letters_to_animate.Count == 0)
			{
				CalculateLettersToAnimate(letters);
			}

			if(json_data.ContainsKey("SAMPLE_NUM_LETTERS_ANIMATED") && m_letters_to_animate != null && m_letters_to_animate.Count > 0)
			{
				timing_scale = m_letters_to_animate.Count / ((float) json_data["SAMPLE_NUM_LETTERS_ANIMATED"].Number);
			}


			LetterAction letter_action;
			num_actions_added = 0;
			foreach(Boomlagoon.JSON.JSONValue action_data in json_data["ACTIONS_DATA"].Array)
			{
				letter_action = new LetterAction();
				letter_action.ImportData(action_data.Obj, assetNameSuffix, timing_scale: timing_scale);

				if(num_actions_added == 0 && action_insert_index > 0)
				{
					// Inserting new actions into the middle of the animation. Set first action to continue from last
					letter_action.m_offset_from_last = true;
				}

				InsertAction(action_insert_index + num_actions_added, letter_action);

				num_actions_added++;
			}


			if (m_loop_cycles == null)
				m_loop_cycles = new List<ActionLoopCycle>();


			num_loops_added = 0;

			if(json_data.ContainsKey("LOOPS_DATA"))
			{
				ActionLoopCycle loop_cycle;
				
				foreach(Boomlagoon.JSON.JSONValue loop_data in json_data["LOOPS_DATA"].Array)
				{
					loop_cycle = new ActionLoopCycle();
					loop_cycle.ImportData(loop_data.Obj);
					loop_cycle.m_start_action_idx += action_insert_index;
					loop_cycle.m_end_action_idx += action_insert_index;

					// Check for invalid loops
					if(loop_cycle.m_start_action_idx < m_letter_actions.Count && loop_cycle.m_end_action_idx < m_letter_actions.Count)
					{
						m_loop_cycles.Insert(loop_insert_index + num_loops_added, loop_cycle);
						
						num_loops_added++;
					}
				}
			}
		}
		public void InsertAction(int index, LetterAction action)
		{
			if(m_letter_actions == null)
				m_letter_actions = new List<LetterAction>();

			if(index >= 0 && index <= m_letter_actions.Count)
				m_letter_actions.Insert(index, action);

			UpdateLoopCyclesAfterIndex (index, 1);
		}
		public void AddAction(LetterAction letter_action, int index)
		{
			if(m_letter_actions == null)
				m_letter_actions = new List<LetterAction>();

			if(index < 0)
				m_letter_actions.Add(letter_action);
			else
				m_letter_actions.Insert(index, letter_action);
		}
		public void AddAction(LetterAction letter_action)
		{
			AddAction (letter_action, -1);
		}