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.Core.DI;
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;
private SynchronizationModuleSettings _settings;
#region Constructors
///
/// Initializes a new instance of the class.
///
/// The navigation.
/// The notification.
public LocalSynchronizationViewVM(SyncNavigationManager navigation, INotificationProvider notification)
{
_settings = SettingsManager.Default.GetOrCreate();
_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(_settings.LocalMasterDBFile))
{
MasterDBFile = _settings.LocalMasterDBFile;
MasterDBName = Path.GetFileName(MasterDBFile);
}
if (File.Exists(_settings.LocalSlaveDBFile))
{
SlaveDBFile = _settings.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 = TangoIOC.Default.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();
_settings.LocalMasterDBFile = MasterDBFile;
_settings.LocalSlaveDBFile = SlaveDBFile;
_settings.Save();
}
}
});
}
///
/// 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
}
}