public SaveFileCharacterViewModelProvider(string savePath)
        {
            InstanceCache   = new List <CharacterViewModel>();
            SaveTimeouTimer = new Timer(FlushSave, null, Timeout.Infinite, Timeout.Infinite);
            SavePath        = savePath;

            var fileBytes = File.ReadAllBytes(savePath);

            //Header
            XDocument scanDocument = Core.LoadHeaderDataXDocument();

            Header      = new DataBlockWrapperBuffer(fileBytes, scanDocument);
            HeaderBytes = new byte[Header.DataBytes.Length];
            Buffer.BlockCopy(Header.DataBytes, 0, HeaderBytes, 0, HeaderBytes.Length);

            //Characters
            int lastChar;
            int numStudents = Header.GetAttribute <int>("HEADER_BOYS") + Header.GetAttribute <int>("HEADER_GIRLS");

            Characters = ReadCharacters(fileBytes, numStudents, out lastChar);

            int footerSize = fileBytes.Length - lastChar;

            FooterBytes = new byte[footerSize];
            Buffer.BlockCopy(fileBytes, lastChar, FooterBytes, 0, footerSize);

            //Player Seat Hax
            var pSeat = new byte[4];

            Buffer.BlockCopy(FooterBytes, FooterBytes.Length - 4, pSeat, 0, 4);
            PlayerSeat = new DataBlockWrapper(pSeat, 0, new SeatDataBlock(), block => Header.HasChanges = true);

            Header.SaveChanges = () =>
            {
                if (!Header.HasChanges)
                {
                    return(false);
                }
                Buffer.BlockCopy(Header.DataBytes, 0, HeaderBytes, 0, HeaderBytes.Length);
                Buffer.BlockCopy(PlayerSeat.DataSource, 0, FooterBytes, FooterBytes.Length - 4, 4);
                StartSaveTimeout();
                Header.HasChanges = false;
                return(true);
            };
            Header.Reload = () =>
            {
                Buffer.BlockCopy(HeaderBytes, 0, Header.DataBytes, 0, Header.DataBytes.Length);
                Buffer.BlockCopy(FooterBytes, FooterBytes.Length - 4, pSeat, 0, 4);
                foreach (DataBlockWrapper block in Header.Attributes.Values)
                {
                    block.DataSource = Header.DataBytes;
                    block.RaisePropertyChanged(String.Empty);
                }
                PlayerSeat.RaisePropertyChanged(String.Empty);
                Header.HasChanges = false;
            };
        }
 public void Dispose()
 {
     SaveTimeouTimer.Dispose();
     InstanceCache.ForEach
         (model =>
     {
         DataBlockWrapperBuffer wb = model.ExtraData["PLAY_DATA"] as DataBlockWrapperBuffer;
         wb.Dispose();
         model.Dispose();
     });
     //throw new NotImplementedException();
 }
        private CharacterViewModel CreateViewModel(CharacterReference reference)
        {
            XDocument scanDocument = Core.LoadPlayDataXDocument();

            CharacterFile cf = CharacterFile.Load(reference.CharBytes);

            CharacterViewModel     vm       = new CharacterViewModel(cf, reference);
            DataBlockWrapperBuffer playData = new DataBlockWrapperBuffer(reference.PlayBytes, scanDocument);

            vm.ExtraData.Add("PLAY_SEAT", reference.Seat);
            vm.ExtraData.Add("PLAY_DATA", playData);

            vm.SaveCommand   = new RelayCommand(() => SaveViewModel(vm), () => SaveViewModelCanExecute(vm));
            vm.ReloadCommand = new RelayCommand(() => ReloadViewModel(vm));

            InstanceCache.Add(vm);

            return(vm);
        }
        private void SaveViewModel(CharacterViewModel vm)
        {
            CharacterReference @ref = (CharacterReference)vm.Metadata;

            CharacterFile          cf = vm.Character;
            DataBlockWrapperBuffer pd = (DataBlockWrapperBuffer)vm.ExtraData["PLAY_DATA"];

            if (cf.HasChanges)
            {
                //[Var]Card Bytes + [3011]Data Bytes + [4]Thumb Lenght + [Var]Thumb Bytes + [4] Data Lenght Mark
                int          newCharBytesLen = cf.CardBytes.Length + cf.DataBytes.Length + cf.ThumbBytes.Length + 8;
                var          newCharData     = new byte[newCharBytesLen];
                MemoryStream ms = new MemoryStream(newCharData);
                // Card Bytes
                ms.Write(cf.CardBytes, 0, cf.CardBytes.Length);
                // Data Bytes
                ms.Write(cf.DataBytes, 0, cf.DataBytes.Length);
                // Thumbnail Lenght
                ms.Write(BitConverter.GetBytes(cf.ThumbBytes.Length), 0, 4);
                // Thumbnail Lenght
                ms.Write(cf.ThumbBytes, 0, cf.ThumbBytes.Length);
                // Identifier Mark
                int lastBytes = cf.DataBytes.Length + cf.ThumbBytes.Length + 8;
                ms.Write(BitConverter.GetBytes(lastBytes), 0, 4);
                ms.Flush();
                @ref.CharBytes = newCharData;
                cf.CardChanges = cf.DataChanges = cf.ThumbChanges = false;
            }

            if (pd.HasChanges)
            {
                var newPlayBytes = new byte[pd.DataBytes.Length];
                Buffer.BlockCopy(pd.DataBytes, 0, newPlayBytes, 0, newPlayBytes.Length);
                @ref.PlayBytes = newPlayBytes;
                pd.HasChanges  = false;
            }

            @ref.Female = (byte)vm.Profile.Gender.Value == 1;

            SaveTimeouTimer.Change(1000, Timeout.Infinite);
        }
        private bool SaveViewModelCanExecute(CharacterViewModel vm)
        {
            DataBlockWrapperBuffer pd = (DataBlockWrapperBuffer)vm.ExtraData["PLAY_DATA"];

            return(pd.HasChanges || !vm.IsDisposed && vm.Character.HasChanges);
        }