/// <summary>
        /// Adds summury information for given remapping.
        /// </summary>
        /// <param name="remap">Remapping object</param>
        /// <param name="lastRemap">Time of previous remapping</param>
        private void AddSummaryForRemapping(AttributesOptimizer.RemappingResult remap, ref TimeSpan lastRemap)
        {
            // Create the group
            string        text  = remap.ToString(m_character) + " at " + Skill.TimeSpanToDescriptiveText(remap.StartTime, DescriptiveTextOptions.IncludeCommas);
            ListViewGroup group = new ListViewGroup(text);

            this.lvPoints.Groups.Add(group);

            // Add five items, one for each attribute
            AddItemForAttribute(remap, group, EveAttribute.Intelligence);
            AddItemForAttribute(remap, group, EveAttribute.Perception);
            AddItemForAttribute(remap, group, EveAttribute.Charisma);
            AddItemForAttribute(remap, group, EveAttribute.Willpower);
            AddItemForAttribute(remap, group, EveAttribute.Memory);

            // Check there are at least one year between each remap
            TimeSpan timeSinceLastRemap = remap.StartTime - lastRemap;

            if (timeSinceLastRemap < TimeSpan.FromDays(365.0) && lastRemap != TimeSpan.Zero)
            {
                var item = new ListViewItem("The previous remap was only " + Skill.TimeSpanToDescriptiveText(timeSinceLastRemap, DescriptiveTextOptions.IncludeCommas) + " ago.", group);
                item.ForeColor = Color.DarkRed;
                lvPoints.Items.Add(item);
            }

            lastRemap = remap.StartTime;
        }
        /// <summary>
        /// Updates controls on the form.
        /// </summary>
        /// <param name="remapping">An <see cref="AttributesOptimizer.Remapping"/> object</param>
        /// <param name="remappingList">List of remappings</param>
        private void UpdateForm(AttributesOptimizer.RemappingResult remapping, List <AttributesOptimizer.RemappingResult> remappingList)
        {
            // If the thread has been canceled, we stop right now to prevent an exception
            if (m_thread == null)
            {
                return;
            }

            // Hide the throbber and the waiting message
            this.throbber.State    = ThrobberState.Stopped;
            this.panelWait.Visible = false;

            // Update the attributes
            if (remapping != null)
            {
                m_statisticsScratchpad = remapping.BestScratchpad.Clone();
                UpdateForRemapping(remapping);
            }
            else
            {
                UpdateForRemappingList(remappingList);
            }

            // Update the plan order's column
            if (m_planEditor != null && (remapping != null || remappingList.Count != 0))
            {
                this.m_planEditor.ShowWithPluggable(this);
            }

            m_thread = null;
        }
        /// <summary>
        /// Updates the UI once the computation has been done (for whole plan or character from birth)
        /// </summary>
        /// <param name="remapping"></param>
        private void UpdateForRemapping(AttributesOptimizer.RemappingResult remapping)
        {
            // Create control
            var ctl = CreateAttributesOptimizationControl(remapping);

            this.Controls.Add(ctl);
            ctl.BringToFront();
        }
        /// <summary>
        /// Initializes a new instance of <see cref="AttributesOptimizationControl"/>.
        /// </summary>
        /// <param name="character">Character information</param>
        /// <param name="remapping">Optimized remapping</param>
        public AttributesOptimizationControl(Character character, AttributesOptimizer.RemappingResult remapping)
        {
            InitializeComponent();

            m_character = character;
            m_remapping = remapping;

            UpdateControls(m_character, m_remapping);
        }
        /// <summary>
        /// Starts optimization.
        /// </summary>
        private void Run()
        {
            // Compute best scratchpad
            var bestDuration = TimeSpan.Zero;

            AttributesOptimizer.RemappingResult        remapping     = null;
            List <AttributesOptimizer.RemappingResult> remappingList = null;

            switch (m_strategy)
            {
            case Strategy.ManualRemappingPointEdition:
                m_areRemappingPointsActive = true;
                if (m_update)
                {
                    remapping = m_remapping;
                    m_manuallyEditedRemappingPoint = remapping.Point.Clone();
                }
                else
                {
                    remapping = AttributesOptimizer.GetResultsFromRemappingPoints(m_plan).Single(x => x.Point == m_manuallyEditedRemappingPoint);
                    m_manuallyEditedRemappingPoint = m_manuallyEditedRemappingPoint.Clone();
                    m_remapping = remapping;
                }
                remapping.Optimize(TimeSpan.MaxValue);
                break;

            case Strategy.Character:
                m_areRemappingPointsActive = false;
                remapping = AttributesOptimizer.OptimizeFromCharacter(m_character, m_plan);
                break;

            case Strategy.OneYearPlan:
                m_areRemappingPointsActive = false;
                remapping = AttributesOptimizer.OptimizeFromFirstYearOfPlan(m_plan);
                break;

            case Strategy.RemappingPoints:
                m_areRemappingPointsActive = true;
                remappingList = AttributesOptimizer.OptimizeFromPlanAndRemappingPoints(m_plan);
                break;

            default:
                throw new NotImplementedException();
            }

            if (m_update)
            {
                // Update the controls for every attribute on the already shown form
                UpdateForm(remapping, remappingList);
            }
            else
            {
                // Update the controls for every attribute
                this.Invoke((MethodInvoker)(() => UpdateForm(remapping, remappingList)));
            }
        }
        /// <summary>
        /// Adds the list item for the given attribute.
        /// </summary>
        /// <param name="remap"></param>
        /// <param name="group"></param>
        /// <param name="attrib"></param>
        private void AddItemForAttribute(AttributesOptimizer.RemappingResult remap, ListViewGroup group, EveAttribute attrib)
        {
            StringBuilder builder    = new StringBuilder(attrib.ToString());
            int           difference = remap.BestScratchpad[attrib].Base - remap.BaseScratchpad[attrib].Base;

            // Add the list view item for this attribute
            string itemText = RemappingPoint.GetStringForAttribute(attrib, remap.BaseScratchpad, remap.BestScratchpad);

            lvPoints.Items.Add(new ListViewItem(itemText, group));
        }
        /// <summary>
        /// Updates bars and labels with given attributes from remapping.
        /// </summary>
        /// <param name="character">Character information</param>
        /// <param name="plan">Skill plan</param>
        /// <param name="remapping">Remapping with attributes and training time</param>
        /// <param name="description"></param>
        private void UpdateControls(Character character, BasePlan plan, AttributesOptimizer.RemappingResult remapping, string description)
        {
            var baseCharacter = character.After(plan.ChosenImplantSet);

            UpdateAttributeControls(baseCharacter, remapping, EveAttribute.Perception, lbPER, pbPERRemappable, pbPERImplants);
            UpdateAttributeControls(baseCharacter, remapping, EveAttribute.Willpower, lbWIL, pbWILRemappable, pbWILImplants);
            UpdateAttributeControls(baseCharacter, remapping, EveAttribute.Memory, lbMEM, pbMEMRemappable, pbMEMImplants);
            UpdateAttributeControls(baseCharacter, remapping, EveAttribute.Intelligence, lbINT, pbINTRemappable, pbINTImplants);
            UpdateAttributeControls(baseCharacter, remapping, EveAttribute.Charisma, lbCHA, pbCHARemappable, pbCHAImplants);

            // Update the description label
            labelDescription.Text = description;

            // Update the current time control
            lbCurrentTime.Text = remapping.BaseDuration.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas);

            // Update the optimized time control
            lbOptimizedTime.Text = remapping.BestDuration.ToDescriptiveText(DescriptiveTextOptions.IncludeCommas);

            // Update the time benefit control
            if (remapping.BestDuration < remapping.BaseDuration)
            {
                lbGain.ForeColor = Color.Black;
                lbGain.Text      = String.Format("{0} better than current",
                                                 remapping.BaseDuration.Subtract(remapping.BestDuration).ToDescriptiveText(DescriptiveTextOptions.IncludeCommas));
            }
            else
            if (remapping.BaseDuration < remapping.BestDuration)
            {
                lbGain.ForeColor = Color.DarkRed;
                lbGain.Text      = String.Format("{0} slower than current",
                                                 remapping.BestDuration.Subtract(remapping.BaseDuration).ToDescriptiveText(DescriptiveTextOptions.IncludeCommas));
            }
            else
            {
                lbGain.ForeColor = Color.Black;
                lbGain.Text      = @"Same as current";
            }

            // A plan may not have a years worth of skills in it,
            // only fair to warn the user
            lbWarning.Visible = remapping.BestDuration < new TimeSpan(365, 0, 0, 0);

            // Spare points
            int sparePoints = EveConstants.SpareAttributePointsOnRemap;

            for (int i = 0; i < 5; i++)
            {
                sparePoints -= (remapping.BestScratchpad[(EveAttribute)i].Base) - EveConstants.CharacterBaseAttributePoints;
            }
            pbUnassigned.Value = sparePoints;

            // If the implant set isn't the active one we notify the user
            lblNotice.Visible = (plan.ChosenImplantSet != character.ImplantSets.Current);
        }
        /// <summary>
        /// Initializes a new instance of <see cref="AttributesOptimizationControl"/>.
        /// </summary>
        /// <param name="character">Character information</param>
        /// <param name="plan">Skill plan</param>
        /// <param name="remapping">Optimized remapping</param>
        /// <param name="description"></param>
        public AttributesOptimizationControl(Character character, BasePlan plan, AttributesOptimizer.RemappingResult remapping, string description)
        {
            InitializeComponent();

            m_character = character;
            m_plan = plan;
            m_remapping = remapping;
            m_description = description;

            UpdateControls(m_character, m_plan, m_remapping, m_description);
        }
        /// <summary>
        /// Initializes a new instance of <see cref="AttributesOptimizationControl"/>.
        /// </summary>
        /// <param name="character">Character information</param>
        /// <param name="plan">Skill plan</param>
        /// <param name="remapping">Optimized remapping</param>
        /// <param name="description"></param>
        public AttributesOptimizationControl(Character character, BasePlan plan, AttributesOptimizer.RemappingResult remapping, string description)
        {
            InitializeComponent();

            m_character   = character;
            m_plan        = plan;
            m_remapping   = remapping;
            m_description = description;

            UpdateControls(m_character, m_plan, m_remapping, m_description);
        }
        /// <summary>
        /// Adds the tab page for the given remapping
        /// </summary>
        /// <param name="remapping"></param>
        /// <param name="tabName"></param>
        private void AddTabPage(AttributesOptimizer.RemappingResult remapping, string tabName)
        {
            var ctl = CreateAttributesOptimizationControl(remapping);

            m_remappingDictionary[ctl] = remapping;

            TabPage page = new TabPage(tabName);

            page.Controls.Add(ctl);

            this.tabControl.TabPages.Add(page);
        }
        /// <summary>
        /// Creates a <see cref="AttributesOptimizationControl"/> for a given remapping.
        /// </summary>
        /// <param name="remapping">The remapping object to represents.</param>
        /// <returns>The created control.</returns>
        private AttributesOptimizationControl CreateAttributesOptimizationControl(AttributesOptimizer.RemappingResult remapping, string description)
        {
            var ctl = new AttributesOptimizationControl(m_character, m_plan, remapping, description);

            ctl.AttributeChanged += new AttributeChangedHandler(AttributesOptimizationControl_AttributeChanged);

            // For a manually edited point, we initialize the control with the attributes from the current remapping point
            if (m_strategy == Strategy.ManualRemappingPointEdition && m_manuallyEditedRemappingPoint.Status == RemappingPoint.PointStatus.UpToDate)
            {
                ctl.UpdateValuesFrom(m_manuallyEditedRemappingPoint);
            }

            return(ctl);
        }
        /// <summary>
        /// Racalculating plan and summary page after change of a <see cref="AttributesOptimizationControl"/>.
        /// </summary>
        /// <param name="control"></param>
        /// <param name="remapping"></param>
        void AttributesOptimizationControl_AttributeChanged(AttributesOptimizationControl control, AttributesOptimizer.RemappingResult remapping)
        {
            // Update the plan order's column
            if (m_planEditor != null)
            {
                if (m_strategy == Strategy.RemappingPoints)
                {
                    m_remappingDictionary[control] = remapping;
                    UpdateSummaryInformation(m_remappingDictionary.Values);
                }

                m_statisticsScratchpad = remapping.BestScratchpad.Clone();
                this.m_planEditor.ShowWithPluggable(this);
            }
        }
        /// <summary>
        /// Reset to remapping with current attributes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonCurrent_Click(object sender, EventArgs e)
        {
            // Make unoptimized remap
            var zeroRemapping = new AttributesOptimizer.RemappingResult(m_remapping, m_remapping.BaseScratchpad.Clone());

            zeroRemapping.Update();

            // Update the controls
            UpdateControls(m_character, zeroRemapping);

            // Fires the event
            if (AttributeChanged != null)
            {
                AttributeChanged(this, zeroRemapping);
            }
        }
        /// <summary>
        /// Updates bars and labels with given attributes from remapping.
        /// </summary>
        /// <param name="character">Character information</param>
        /// <param name="remapping">Remapping with attributes and training time</param>
        private void UpdateControls(Character character, AttributesOptimizer.RemappingResult remapping)
        {
            UpdateAttributeControls(character, remapping, EveAttribute.Perception, lbPER, pbPERBase, pbPERImplants, pbPERSkills);
            UpdateAttributeControls(character, remapping, EveAttribute.Willpower, lbWIL, pbWILBase, pbWILImplants, pbWILSkills);
            UpdateAttributeControls(character, remapping, EveAttribute.Memory, lbMEM, pbMEMBase, pbMEMImplants, pbMEMSkills);
            UpdateAttributeControls(character, remapping, EveAttribute.Intelligence, lbINT, pbINTBase, pbINTImplants, pbINTSkills);
            UpdateAttributeControls(character, remapping, EveAttribute.Charisma, lbCHA, pbCHABase, pbCHAImplants, pbCHASkills);

            // Update the current time control
            this.lbCurrentTime.Text = Skill.TimeSpanToDescriptiveText(remapping.BaseDuration, DescriptiveTextOptions.IncludeCommas);

            // Update the optimized time control
            this.lbOptimizedTime.Text = Skill.TimeSpanToDescriptiveText(remapping.BestDuration, DescriptiveTextOptions.IncludeCommas);

            // Update the time benefit control
            if (remapping.BestDuration < remapping.BaseDuration)
            {
                this.lbGain.ForeColor = Color.Black;
                this.lbGain.Text      = Skill.TimeSpanToDescriptiveText(remapping.BaseDuration - remapping.BestDuration,
                                                                        DescriptiveTextOptions.IncludeCommas) + " better than current";
            }
            else
            if (remapping.BaseDuration < remapping.BestDuration)
            {
                this.lbGain.ForeColor = Color.DarkRed;
                this.lbGain.Text      = Skill.TimeSpanToDescriptiveText(remapping.BestDuration - remapping.BaseDuration,
                                                                        DescriptiveTextOptions.IncludeCommas) + " slower than current";
            }
            else
            {
                this.lbGain.ForeColor = Color.Black;
                this.lbGain.Text      = "Same as current";
            }

            // A plan may not have a years worth of skills in it,
            // only fair to warn the user
            this.lbWarning.Visible = remapping.BestDuration < new TimeSpan(365, 0, 0, 0);

            // Spare points
            int sparePoints = EveConstants.SpareAttributePointsOnRemap;

            for (int i = 0; i < 5; i++)
            {
                sparePoints -= (remapping.BestScratchpad[(EveAttribute)i].Base - EveConstants.MinAttributeValueOnRemap);
            }
            pbUnassigned.Value = sparePoints;
        }
        /// <summary>
        /// Calculates new remapping from values of controls.
        /// </summary>
        public void Recalculate()
        {
            var scratchpad = m_remapping.BaseScratchpad.Clone();
            scratchpad.Memory.Base = pbMEMRemappable.Value + EveConstants.CharacterBaseAttributePoints;
            scratchpad.Charisma.Base = pbCHARemappable.Value + EveConstants.CharacterBaseAttributePoints;
            scratchpad.Willpower.Base = pbWILRemappable.Value + EveConstants.CharacterBaseAttributePoints;
            scratchpad.Perception.Base = pbPERRemappable.Value + EveConstants.CharacterBaseAttributePoints;
            scratchpad.Intelligence.Base = pbINTRemappable.Value + EveConstants.CharacterBaseAttributePoints;

            // Get remapping for provided attributes
            var manualRemapping = new AttributesOptimizer.RemappingResult(m_remapping, scratchpad);
            manualRemapping.Update();
            UpdateControls(m_character, m_plan, manualRemapping, m_description);

            // Notify the changes
            if (AttributeChanged != null)
                AttributeChanged(this, manualRemapping);
        }
        /// <summary>
        /// Updates bars and labels for specified attribute.
        /// </summary>
        /// <param name="character">Character information</param>
        /// <param name="remapping">Attribute remapping</param>
        /// <param name="attrib">Attribute that will be used to update controls</param>
        /// <param name="lb">Label control</param>
        /// <param name="pbRemappable">Attribute bar for remappable value</param>
        /// <param name="pbImplants">Attribute bar for implants</param>
        private void UpdateAttributeControls(
            BaseCharacter character,
            AttributesOptimizer.RemappingResult remapping,
            EveAttribute attrib,
            Label lb,
            AttributeBarControl pbRemappable,
            AttributeBarControl pbImplants)
        {
            // Compute base and effective attributes
            int effectiveAttribute  = remapping.BestScratchpad[attrib].EffectiveValue;
            int oldBaseAttribute    = remapping.BaseScratchpad[attrib].Base;
            int remappableAttribute = remapping.BestScratchpad[attrib].Base;
            int implantsBonus       = remapping.BestScratchpad[attrib].ImplantBonus;

            // Update the label
            lb.Text = String.Format("{0} (new : {1} ; old : {2})", effectiveAttribute, remappableAttribute, oldBaseAttribute);

            // Update the bars
            pbRemappable.Value = remappableAttribute - EveConstants.CharacterBaseAttributePoints;
            pbImplants.Value   = implantsBonus;
        }
        /// <summary>
        /// Calculates new remapping from values of controls.
        /// </summary>
        private void Recalculate()
        {
            var scratchpad = m_remapping.BaseScratchpad.Clone();

            scratchpad.Memory.Base       = pbMEMBase.Value;
            scratchpad.Charisma.Base     = pbCHABase.Value;
            scratchpad.Willpower.Base    = pbWILBase.Value;
            scratchpad.Perception.Base   = pbPERBase.Value;
            scratchpad.Intelligence.Base = pbINTBase.Value;

            // Get remapping for provided attributes
            var manualRemapping = new AttributesOptimizer.RemappingResult(m_remapping, scratchpad);

            manualRemapping.Update();
            UpdateControls(m_character, manualRemapping);

            // Notify the changes
            if (AttributeChanged != null)
            {
                AttributeChanged(this, manualRemapping);
            }
        }
        /// <summary>
        /// Calculates new remapping from values of controls.
        /// </summary>
        public void Recalculate()
        {
            var scratchpad = m_remapping.BaseScratchpad.Clone();

            scratchpad.Memory.Base       = pbMEMRemappable.Value + EveConstants.CharacterBaseAttributePoints;
            scratchpad.Charisma.Base     = pbCHARemappable.Value + EveConstants.CharacterBaseAttributePoints;
            scratchpad.Willpower.Base    = pbWILRemappable.Value + EveConstants.CharacterBaseAttributePoints;
            scratchpad.Perception.Base   = pbPERRemappable.Value + EveConstants.CharacterBaseAttributePoints;
            scratchpad.Intelligence.Base = pbINTRemappable.Value + EveConstants.CharacterBaseAttributePoints;

            // Get remapping for provided attributes
            var manualRemapping = new AttributesOptimizer.RemappingResult(m_remapping, scratchpad);

            manualRemapping.Update();
            UpdateControls(m_character, m_plan, manualRemapping, m_description);

            // Notify the changes
            if (AttributeChanged != null)
            {
                AttributeChanged(this, manualRemapping);
            }
        }
        /// <summary>
        /// Updates the controls with the values from the current remapping point.
        /// </summary>
        /// <param name="point"></param>
        public void UpdateValuesFrom(RemappingPoint point)
        {
            // Creates a scratchpad with the base values from the provided point.
            var scratchpad = new CharacterScratchpad(m_character);

            for (int i = 0; i < 5; i++)
            {
                scratchpad[(EveAttribute)i].Base = point[(EveAttribute)i];
            }

            var remapping = new AttributesOptimizer.RemappingResult(m_remapping, scratchpad);

            remapping.Update();

            // Update the controls
            UpdateControls(m_character, remapping);

            // Fires the event
            if (AttributeChanged != null)
            {
                AttributeChanged(this, remapping);
            }
        }
        /// <summary>
        /// Updates bars and labels for specified attribute.
        /// </summary>
        /// <param name="character">Character information</param>
        /// <param name="remapping">Attribute remapping</param>
        /// <param name="attrib">Attribute that will be used to update controls</param>
        /// <param name="lb">Label control</param>
        /// <param name="pbBase">Attribute bar for base value</param>
        /// <param name="pbImplants">Attribute bar for implants</param>
        /// <param name="pbSkills">Attribute bar for skills</param>
        private void UpdateAttributeControls(
            Character character,
            AttributesOptimizer.RemappingResult remapping,
            EveAttribute attrib,
            Label lb,
            AttributeBarControl pbBase,
            AttributeBarControl pbImplants,
            AttributeBarControl pbSkills)
        {
            // Compute base and effective attributes
            float effectiveAttribute = remapping.BestScratchpad[attrib].EffectiveValue;
            int   oldBaseAttribute   = remapping.BaseScratchpad[attrib].Base;
            int   baseAttribute      = remapping.BestScratchpad[attrib].Base;
            int   implantsBonus      = remapping.BestScratchpad[attrib].ImplantBonus;
            int   skillsBonus        = (int)effectiveAttribute - (baseAttribute + implantsBonus);

            // Update the label
            lb.Text = effectiveAttribute.ToString("##.##") + " (new : " + baseAttribute.ToString() + " ; old : " + oldBaseAttribute.ToString() + ")";

            // Update the bars
            pbBase.Value     = baseAttribute;
            pbImplants.Value = implantsBonus;
            pbSkills.Value   = skillsBonus;
        }
        /// <summary>
        /// Reset to remapping with current attributes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void buttonCurrent_Click(object sender, EventArgs e)
        {
            // Make unoptimized remap
            var zeroRemapping = new AttributesOptimizer.RemappingResult(m_remapping, m_remapping.BaseScratchpad.Clone());
            zeroRemapping.Update();

            // Update the controls
            UpdateControls(m_character, m_plan, zeroRemapping, m_description);

            // Fires the event
            if (AttributeChanged != null)
                AttributeChanged(this, zeroRemapping);
        }
        /// <summary>
        /// Racalculating plan and summary page after change of a <see cref="AttributesOptimizationControl"/>.
        /// </summary>
        /// <param name="control"></param>
        /// <param name="remapping"></param>
        void AttributesOptimizationControl_AttributeChanged(AttributesOptimizationControl control, AttributesOptimizer.RemappingResult remapping)
        {
            // Update the plan order's column
            if (m_planEditor != null)
            {
                if (m_strategy == Strategy.RemappingPoints)
                {
                    m_remappingDictionary[control] = remapping;
                    UpdateSummaryInformation(m_remappingDictionary.Values);
                }

                m_statisticsScratchpad = remapping.BestScratchpad.Clone();
                this.m_planEditor.ShowWithPluggable(this);
                m_remapping = remapping;
            }
        }
        /// <summary>
        /// Updates the controls with the values from the current remapping point.
        /// </summary>
        /// <param name="point"></param>
        public void UpdateValuesFrom(RemappingPoint point)
        {
            // Creates a scratchpad with the base values from the provided point.
            var scratchpad = new CharacterScratchpad(m_character.After(m_plan.ChosenImplantSet));
            for (int i = 0; i < 5; i++)
            {
                scratchpad[(EveAttribute)i].Base = point[(EveAttribute)i];
            }

            var remapping = new AttributesOptimizer.RemappingResult(m_remapping, scratchpad);
            remapping.Update();

            // Update the controls
            UpdateControls(m_character, m_plan, remapping, m_description);

            // Fires the event
            if (AttributeChanged != null)
                AttributeChanged(this, remapping);
        }
        /// <summary>
        /// Starts optimization.
        /// </summary>
        private void Run()
        {
            // Compute best scratchpad
            var bestDuration = TimeSpan.Zero;
            AttributesOptimizer.RemappingResult remapping = null;
            List<AttributesOptimizer.RemappingResult> remappingList = null;

            switch (m_strategy)
            {
                case Strategy.ManualRemappingPointEdition:
                    m_areRemappingPointsActive = true;
                    if (m_update)
                    {
                        remapping = m_remapping;
                        m_manuallyEditedRemappingPoint = remapping.Point.Clone();
                    }
                    else
                    {
                        remapping = AttributesOptimizer.GetResultsFromRemappingPoints(m_plan).Single(x => x.Point == m_manuallyEditedRemappingPoint);
                        m_manuallyEditedRemappingPoint = m_manuallyEditedRemappingPoint.Clone();
                        m_remapping = remapping;
                    }
                    remapping.Optimize(TimeSpan.MaxValue);
                    break;
                case Strategy.Character:
                    m_areRemappingPointsActive = false;
                    remapping = AttributesOptimizer.OptimizeFromCharacter(m_character, m_plan);
                    break;
                case Strategy.OneYearPlan:
                    m_areRemappingPointsActive = false;
                    remapping = AttributesOptimizer.OptimizeFromFirstYearOfPlan(m_plan);
                    break;
                case Strategy.RemappingPoints:
                    m_areRemappingPointsActive = true;
                    remappingList = AttributesOptimizer.OptimizeFromPlanAndRemappingPoints(m_plan);
                    break;
                default:
                    throw new NotImplementedException();
            }

            if (m_update)
            {
                // Update the controls for every attribute on the already shown form
                UpdateForm(remapping, remappingList);
            }
            else
            {
                // Update the controls for every attribute
                this.Invoke((MethodInvoker)(() => UpdateForm(remapping, remappingList)));
            }
        }