public IEnumerable <IResult> CopySelectedSlotCode()
        {
            yield return(new DelegateResult(
                             () =>
            {
                if (this.SelectedSlot == null ||
                    this.SelectedSlot.BackpackSlot == null)
                {
                    if (MyClipboard.SetText("") != MyClipboard.Result.Success)
                    {
                        MessageBox.Show(
                            "Clipboard failure.",
                            "Error",
                            MessageBoxButton.OK,
                            MessageBoxImage.Error);
                    }
                    return;
                }

                // just a hack until I add a way to override the unique ID in Encode()
                var copy = (IPackableSlot)this.SelectedSlot.BackpackSlot.Clone();
                copy.UniqueId = 0;

                var data = BackpackDataHelper.Encode(copy, Platform.PC);
                var sb = new StringBuilder();
                sb.Append("BLOZ(");
                sb.Append(Convert.ToBase64String(data, Base64FormattingOptions.None));
                sb.Append(")");

                /*
                 * if (MyClipboard.SetText(sb.ToString()) != MyClipboard.Result.Success)
                 * {
                 *  MessageBox.Show("Clipboard failure.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                 * }
                 */

                var dobj = new DataObject();
                dobj.SetText(sb.ToString());
                if (MyClipboard.SetDataObject(dobj, false) != MyClipboard.Result.Success)
                {
                    MessageBox.Show(
                        "Clipboard failure.",
                        "Error",
                        MessageBoxButton.OK,
                        MessageBoxImage.Error);
                }
            }));
        }
        public IEnumerable <IResult> PasteCode()
        {
            bool containsText;
            bool containsUnicodeText = false;

            if (MyClipboard.ContainsText(TextDataFormat.Text, out containsText) != MyClipboard.Result.Success ||
                MyClipboard.ContainsText(TextDataFormat.UnicodeText, out containsUnicodeText) !=
                MyClipboard.Result.Success)
            {
                yield return(new MyMessageBox("Clipboard failure.", "Error")
                             .WithIcon(MessageBoxImage.Error));
            }

            if (containsText == false &&
                containsUnicodeText == false)
            {
                yield break;
            }

            var errors     = 0;
            var viewModels = new List <IBaseSlotViewModel>();

            yield return(new DelegateResult(
                             () =>
            {
                string codes;
                if (MyClipboard.GetText(out codes) != MyClipboard.Result.Success)
                {
                    MessageBox.Show("Clipboard failure.",
                                    "Error",
                                    MessageBoxButton.OK,
                                    MessageBoxImage.Error);
                    return;
                }

                // strip whitespace
                codes = Regex.Replace(codes, @"\s+", "");

                foreach (var match in _CodeSignature.Matches(codes).Cast <Match>()
                         .Where(m => m.Success == true))
                {
                    var code = match.Groups["data"].Value;

                    IPackableSlot packable;

                    try
                    {
                        var data = Convert.FromBase64String(code);
                        packable = BaseDataHelper.Decode(data, Platform.PC);
                    }
                    catch (Exception)
                    {
                        errors++;
                        continue;
                    }

                    // TODO: check other item unique IDs to prevent rare collisions
                    packable.UniqueId = new Random().Next(int.MinValue, int.MaxValue);

                    if (packable is BaseWeapon)
                    {
                        var weapon = (BaseWeapon)packable;
                        var viewModel = new BaseWeaponViewModel(weapon);
                        viewModels.Add(viewModel);
                    }
                    else if (packable is BaseItem)
                    {
                        var item = (BaseItem)packable;
                        var viewModel = new BaseItemViewModel(item);
                        viewModels.Add(viewModel);
                    }
                }
            }));

            if (viewModels.Count > 0)
            {
                viewModels.ForEach(vm => this.Slots.Add(vm));
                this.SelectedSlot = viewModels.First();
            }

            if (errors > 0)
            {
                yield return
                    (new MyMessageBox("Failed to load " + errors.ToString(CultureInfo.InvariantCulture) + " codes.",
                                      "Warning")
                     .WithIcon(MessageBoxImage.Warning));
            }
            else if (viewModels.Count == 0)
            {
                yield return
                    (new MyMessageBox("Did not find any codes in clipboard.",
                                      "Warning")
                     .WithIcon(MessageBoxImage.Warning));
            }
        }
        public IEnumerable <IResult> ReadSave()
        {
            string fileName = null;
            var    platform = Platform.Invalid;

            foreach (var result in this.SaveLoad.OpenFile(s => fileName = s, p => platform = p))
            {
                yield return(result);
            }

            if (fileName == null)
            {
                yield break;
            }

            FileFormats.SaveFile saveFile = null;

            yield return(new DelegateResult(
                             () =>
            {
                using (var input = File.OpenRead(fileName))
                {
                    saveFile = FileFormats.SaveFile.Deserialize(
                        input,
                        platform,
                        FileFormats.SaveFile.DeserializeSettings.None);
                }

                try
                {
                    FileFormats.SaveExpansion.ExtractExpansionSavedataFromUnloadableItemData(
                        saveFile.SaveGame);

                    this.General.ImportData(saveFile.SaveGame, saveFile.Platform);
                    this.Character.ImportData(saveFile.SaveGame);
                    this.Vehicle.ImportData(saveFile.SaveGame);
                    this.CurrencyOnHand.ImportData(saveFile.SaveGame);
                    this.Backpack.ImportData(saveFile.SaveGame, saveFile.Platform);
                    this.Bank.ImportData(saveFile.SaveGame, saveFile.Platform);
                    //this.FastTravel.ImportData(saveFile.SaveGame);
                    this.SaveFile = saveFile;
                    this.MaybeSwitchToGeneral();
                }
                catch (Exception)
                {
                    this.SaveFile = null;
                    throw;
                }
            })
                         .Rescue <DllNotFoundException>().Execute(
                             x => new MyMessageBox("Failed to load save: " + x.Message, "Error")
                             .WithIcon(MessageBoxImage.Error).AsCoroutine())
                         .Rescue <FileFormats.SaveFormatException>().Execute(
                             x => new MyMessageBox("Failed to load save: " + x.Message, "Error")
                             .WithIcon(MessageBoxImage.Error).AsCoroutine())
                         .Rescue <FileFormats.SaveCorruptionException>().Execute(
                             x => new MyMessageBox("Failed to load save: " + x.Message, "Error")
                             .WithIcon(MessageBoxImage.Error).AsCoroutine())
                         .Rescue().Execute(
                             x =>
                             new MyMessageBox("An exception was thrown (press Ctrl+C to copy):\n\n" + x.ToString(),
                                              "Error")
                             .WithIcon(MessageBoxImage.Error).AsCoroutine()));


            if (saveFile != null &&
                saveFile.SaveGame.IsBadassModeSaveGame == true)
            {
                saveFile.SaveGame.IsBadassModeSaveGame = false;
                yield return
                    (new MyMessageBox("Your save file was set as 'Badass Mode', and this has now been cleared.\n\n" +
                                      "See http://bit.ly/graveyardsav for more details.",
                                      "Information")
                     .WithIcon(MessageBoxImage.Information));
            }


            if (this.SaveFile != null &&
                this.Backpack.BrokenWeapons.Count > 0)
            {
                var result = MessageBoxResult.No;
                do
                {
                    yield return
                        (new MyMessageBox(
                             "There were weapons in the backpack that failed to load. Do you want to remove them?\n\n" +
                             "If you choose not to remove them, they will remain in your save but will not be editable." +
                             (result != MessageBoxResult.Cancel
                                 ? "\n\nChoose Cancel to copy error information to the clipboard."
                                 : ""),
                             "Warning")
                         .WithButton(result != MessageBoxResult.Cancel
                                            ? MessageBoxButton.YesNoCancel
                                            : MessageBoxButton.YesNo)
                         .WithDefaultResult(MessageBoxResult.No)
                         .WithResultDo(r => result = r)
                         .WithIcon(MessageBoxImage.Warning));

                    if (result == MessageBoxResult.Yes)
                    {
                        this.Backpack.BrokenWeapons.Clear();
                    }
                    else if (result == MessageBoxResult.Cancel)
                    {
                        var sb = new StringBuilder();
                        this.Backpack.BrokenWeapons.ForEach(kv =>
                        {
                            sb.AppendLine(kv.Value.ToString());
                            sb.AppendLine();
                        });
                        if (MyClipboard.SetText(sb.ToString()) != MyClipboard.Result.Success)
                        {
                            MessageBox.Show("Clipboard failure.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        }
                    }
                }while (result == MessageBoxResult.Cancel);
            }

            if (this.SaveFile != null &&
                this.Backpack.BrokenItems.Count > 0)
            {
                var result = MessageBoxResult.No;
                do
                {
                    yield return
                        (new MyMessageBox(
                             "There were items in the backpack that failed to load. Do you want to remove them?\n\n" +
                             "If you choose not to remove them, they will remain in your save but will not be editable." +
                             (result != MessageBoxResult.Cancel
                                 ? "\n\nChoose Cancel to copy error information to the clipboard."
                                 : ""),
                             "Warning")
                         .WithButton(result != MessageBoxResult.Cancel
                                            ? MessageBoxButton.YesNoCancel
                                            : MessageBoxButton.YesNo)
                         .WithDefaultResult(MessageBoxResult.No)
                         .WithResultDo(r => result = r)
                         .WithIcon(MessageBoxImage.Warning));

                    if (result == MessageBoxResult.Yes)
                    {
                        this.Backpack.BrokenItems.Clear();
                    }
                    else if (result == MessageBoxResult.Cancel)
                    {
                        var sb = new StringBuilder();
                        this.Backpack.BrokenItems.ForEach(kv =>
                        {
                            sb.AppendLine(kv.Value.ToString());
                            sb.AppendLine();
                        });
                        if (MyClipboard.SetText(sb.ToString()) != MyClipboard.Result.Success)
                        {
                            MessageBox.Show("Clipboard failure.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        }
                    }
                }while (result == MessageBoxResult.Cancel);
            }

            if (this.SaveFile != null &&
                this.Bank.BrokenSlots.Count > 0)
            {
                var result = MessageBoxResult.No;
                do
                {
                    yield return
                        (new MyMessageBox(
                             "There were weapons or items in the bank that failed to load. Do you want to remove them?\n\n" +
                             "If you choose not to remove them, they will remain in your save but will not be editable." +
                             (result != MessageBoxResult.Cancel
                                 ? "\n\nChoose Cancel to copy error information to the clipboard."
                                 : ""),
                             "Warning")
                         .WithButton(result != MessageBoxResult.Cancel
                                            ? MessageBoxButton.YesNoCancel
                                            : MessageBoxButton.YesNo)
                         .WithDefaultResult(MessageBoxResult.No)
                         .WithResultDo(r => result = r)
                         .WithIcon(MessageBoxImage.Warning));

                    if (result == MessageBoxResult.Yes)
                    {
                        this.Bank.BrokenSlots.Clear();
                    }
                    else if (result == MessageBoxResult.Cancel)
                    {
                        var sb = new StringBuilder();
                        this.Bank.BrokenSlots.ForEach(kv =>
                        {
                            sb.AppendLine(kv.Value.ToString());
                            sb.AppendLine();
                        });
                        if (MyClipboard.SetText(sb.ToString()) != MyClipboard.Result.Success)
                        {
                            MessageBox.Show("Clipboard failure.", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                        }
                    }
                }while (result == MessageBoxResult.Cancel);
            }
        }