using Microsoft.Practices.ServiceLocation; using Microsoft.Win32; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using Tango.Core.Commands; using Tango.Logging; using Tango.MachineStudio.Common.Notifications; using Tango.MachineStudio.Synchronization.Navigation; using Tango.MachineStudio.Synchronization.Properties; using Tango.Settings; using Tango.SharedUI; using Tango.Synchronization; using Tango.Synchronization.Local; namespace Tango.MachineStudio.Synchronization.ViewModels { /// /// Represents the 'Local Synchronization' view model. /// /// public class LocalSynchronizationViewVM : ViewModel { private SyncNavigationManager _navigation; private String _masterDBFile; private String _slaveDBFile; private LocalDBComparer _comparer; private INotificationProvider _notification; private bool _isWorking; private MainViewVM _mainView; #region Constructors /// /// Initializes a new instance of the class. /// /// The navigation. /// The notification. public LocalSynchronizationViewVM(SyncNavigationManager navigation, INotificationProvider notification) { _navigation = navigation; _notification = notification; BackCommand = new RelayCommand(() => _navigation.NavigateTo(NavigationView.MenuView)); Differences = new ObservableCollection(); BrowseMasterDBCommand = new RelayCommand(BrowseMasterDB, (x) => !_isWorking); BrowseSlaveDBCommand = new RelayCommand(BrowseSlaveDB, (x) => !_isWorking); CompareCommand = new RelayCommand(Compare, (x) => MasterDBFile != null && SlaveDBFile != null && !_isWorking); CommitCommand = new RelayCommand(Commit, (x) => SelectedDifference != null && !_isWorking); CommitAllCommand = new RelayCommand(CommitAll, (x) => Differences.Count > 0 && !_isWorking); CleanCommand = new RelayCommand(CleanSlave, (x) => !_isWorking && SlaveDBFile != null); if (File.Exists(SettingsManager.Default.MachineStudio.SynchronizationModule.LocalMasterDBFile)) { MasterDBFile = SettingsManager.Default.MachineStudio.SynchronizationModule.LocalMasterDBFile; MasterDBName = Path.GetFileName(MasterDBFile); } if (File.Exists(SettingsManager.Default.MachineStudio.SynchronizationModule.LocalSlaveDBFile)) { SlaveDBFile = SettingsManager.Default.MachineStudio.SynchronizationModule.LocalSlaveDBFile; SlaveDBName = Path.GetFileName(SlaveDBFile); } } #endregion #region Commands /// /// Gets or sets the back command. /// public RelayCommand BackCommand { get; set; } /// /// Gets or sets the browse master database command. /// public RelayCommand BrowseMasterDBCommand { get; set; } /// /// Gets or sets the browse slave database command. /// public RelayCommand BrowseSlaveDBCommand { get; set; } /// /// Gets or sets the compare command. /// public RelayCommand CompareCommand { get; set; } /// /// Gets or sets the commit command. /// public RelayCommand CommitCommand { get; set; } /// /// Gets or sets the commit all command. /// public RelayCommand CommitAllCommand { get; set; } /// /// Gets or sets the clean command. /// public RelayCommand CleanCommand { get; set; } #endregion #region Properties private ObservableCollection _differences; /// /// Gets or sets the differences. /// public ObservableCollection Differences { get { return _differences; } set { _differences = value; RaisePropertyChanged(nameof(Differences)); } } private Diff _selectedDifference; /// /// Gets or sets the selected difference. /// public Diff SelectedDifference { get { return _selectedDifference; } set { _selectedDifference = value; RaisePropertyChanged(nameof(SelectedDifference)); InvalidateRelayCommands(); } } private String _masterDBName; /// /// Gets or sets the name of the master database. /// public String MasterDBName { get { return _masterDBName; } set { _masterDBName = value; RaisePropertyChanged(nameof(MasterDBName)); } } private String _slaveDBName; /// /// Gets or sets the name of the slave database. /// public String SlaveDBName { get { return _slaveDBName; } set { _slaveDBName = value; RaisePropertyChanged(nameof(SlaveDBName)); } } /// /// Gets or sets the slave database file. /// public String SlaveDBFile { get { return _slaveDBFile; } set { _slaveDBFile = value; RaisePropertyChangedAuto(); } } /// /// Gets or sets the master database file. /// public String MasterDBFile { get { return _masterDBFile; } set { _masterDBFile = value; RaisePropertyChangedAuto(); } } #endregion #region Event Handlers private void Comparer_Progress(object sender, string e) { if (_mainView == null) { _mainView = ServiceLocator.Current.GetInstance(); _mainView.Log = String.Empty; } _mainView.Log += ("[" + DateTime.Now.ToTimeString() + "] " + e + Environment.NewLine); } #endregion #region Private Methods /// /// Cleans the slave database. /// private async void CleanSlave() { if (_notification.ShowQuestion("Are you sure you want to erase all data on slave database?")) { using (_notification.PushTaskItem("Clearing database...")) { try { _isWorking = true; await Task.Factory.StartNew(() => { SQLiteDataBase localDB = new SQLiteDataBase(SlaveDBFile); localDB.LoadTables(); localDB.ClearDataBase(); try { localDB.Dispose(); } catch { } }); Differences.Clear(); } catch (Exception ex) { ShowError(LogManager.Log(ex).Message); } finally { _isWorking = false; InvalidateRelayCommands(); SelectedDifference = null; } } } } /// /// Compares the master and slave database files. /// private void Compare() { _comparer = new LocalDBComparer(new SQLiteDataBase(MasterDBFile), new SQLiteDataBase(SlaveDBFile)); _comparer.Progress += Comparer_Progress; Task.Factory.StartNew(() => { using (_notification.PushTaskItem("Comparing Databases...")) { try { _isWorking = true; InvalidateRelayCommands(); Thread.Sleep(1500); var diffs = _comparer.Compare(); Differences = new ObservableCollection(diffs); if (diffs.Where(x => x.Action != DiffAction.ReplaceTableDataInSlave).Count() > 0) { ShowInfo("Found " + Differences.Where(x => x.Action != DiffAction.ReplaceTableDataInSlave).Count() + " differences."); } else { ShowInfo("The master and slave databases are synchronized."); } } catch (Exception ex) { ShowError(ex.Message); } finally { _isWorking = false; SelectedDifference = null; InvalidateRelayCommands(); SettingsManager.Default.MachineStudio.SynchronizationModule.LocalMasterDBFile = MasterDBFile; SettingsManager.Default.MachineStudio.SynchronizationModule.LocalSlaveDBFile = SlaveDBFile; SettingsManager.SaveDefaultSettings(); } } }); } /// /// Commits the selected difference. /// private void Commit() { Task.Factory.StartNew(() => { using (_notification.PushTaskItem("Committing difference...")) { try { _isWorking = true; InvalidateRelayCommands(); Thread.Sleep(1500); SelectedDifference.Commit(); InvokeUINow(() => Differences.Remove(SelectedDifference)); } catch (Exception ex) { ShowError(ex.Message); } finally { _isWorking = false; SelectedDifference = null; InvalidateRelayCommands(); } } }); } /// /// Commits all the differences. /// private void CommitAll() { Task.Factory.StartNew(() => { using (_notification.PushTaskItem("Committing all differences...")) { try { _isWorking = true; InvalidateRelayCommands(); Thread.Sleep(1500); for (int i = 0; i < Differences.Count; i++) { var diff = Differences[i]; using (_notification.PushTaskItem("Committing difference " + (Differences.IndexOf(diff) + 1) + "...")) { diff.Commit(); InvokeUINow(() => Differences.Remove(diff)); i--; } } } catch (Exception ex) { ShowError(ex.Message); } finally { _isWorking = false; SelectedDifference = null; InvalidateRelayCommands(); } } }); } /// /// Browse for slave database file. /// private void BrowseSlaveDB() { String file = BrowseForFilePath(); if (file != null) { SlaveDBFile = file; SlaveDBName = Path.GetFileName(file); InvalidateRelayCommands(); } } /// /// Browse for master database file. /// private void BrowseMasterDB() { String file = BrowseForFilePath(); if (file != null) { MasterDBFile = file; MasterDBName = Path.GetFileName(file); InvalidateRelayCommands(); } } /// /// Browse for database file. /// private String BrowseForFilePath() { OpenFileDialog dlg = new OpenFileDialog(); dlg.Title = "Select SQLite Database File"; dlg.Filter = "SQLite Database|*.db"; if (dlg.ShowDialog().Value) { return dlg.FileName; } return null; } /// /// Displays an error message. /// /// The message. private void ShowError(String message) { InvokeUINow(() => _notification.ShowError(message)); } /// /// Displays an information message. /// /// The message. private void ShowInfo(String message) { InvokeUINow(() => _notification.ShowInfo(message)); } #endregion } }