using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Data.Entity.Validation;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Tango.Core.Commands;
using Tango.DAL.Local.DB;
using Tango.BL.Entities;
using Tango.DAL.Remote.DB;
using Tango.Logging;
using Tango.MachineStudio.Common.Notifications;
using Tango.MachineStudio.Common.StudioApplication;
using Tango.MachineStudio.Synchronization.Navigation;
using Tango.Settings;
using Tango.SharedUI;
using Tango.Synchronization;
using Tango.Synchronization.Local;
using Tango.Synchronization.Remote;
using Microsoft.Practices.ServiceLocation;
namespace Tango.MachineStudio.Synchronization.ViewModels
{
///
/// Represents the 'Semi Remote Synchronization' view model.
///
///
///
public class RemoteSynchronizationViewVM : ViewModel, IShutdownRequestBlocker
{
private SyncNavigationManager _navigation;
private String _slaveDBFile;
private INotificationProvider _notification;
private bool _isWorking;
private RemoteDBComparer _comparer;
private RemoteDB _remoteDB;
private LocalDB _localDB;
private MainViewVM _mainView;
#region Constructors
///
/// Initializes a new instance of the class.
///
/// The navigation.
/// The notification.
public RemoteSynchronizationViewVM(SyncNavigationManager navigation, INotificationProvider notification)
{
_navigation = navigation;
_notification = notification;
BackCommand = new RelayCommand(() => _navigation.NavigateTo(NavigationView.MenuView));
Differences = new ObservableCollection();
BrowseSlaveDBCommand = new RelayCommand(BrowseSlaveDB, (x) => !_isWorking);
CompareCommand = new RelayCommand(Compare, (x) => SlaveDBFile != null && !_isWorking && SelectedMachine != null);
CommitCommand = new RelayCommand(Commit, (x) => SelectedDifference != null && !_isWorking && SelectedMachine != null);
CommitAllCommand = new RelayCommand(CommitAll, (x) => Differences.Count > 0 && !_isWorking && SelectedMachine != null);
CleanCommand = new RelayCommand(CleanSlave, (x) => !_isWorking && SlaveDBFile != null);
if (File.Exists(SettingsManager.Default.MachineStudio.SynchronizationModule.RemoteSQLiteFile))
{
SlaveDBFile = SettingsManager.Default.MachineStudio.SynchronizationModule.RemoteSQLiteFile;
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 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 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 _slaveDBName;
///
/// Gets or sets the name of the slave database.
///
public String SlaveDBName
{
get { return _slaveDBName; }
set { _slaveDBName = value; RaisePropertyChanged(nameof(SlaveDBName)); }
}
private Machine _selectedMachine;
///
/// Gets or sets the selected machine.
///
public Machine SelectedMachine
{
get { return _selectedMachine; }
set { _selectedMachine = value; RaisePropertyChangedAuto(); InvalidateRelayCommands(); }
}
///
/// Gets or sets the slave database file.
///
public String SlaveDBFile
{
get { return _slaveDBFile; }
set { _slaveDBFile = value; RaisePropertyChangedAuto(); }
}
#endregion
#region Private Methods
///
/// Cleans the slave database file.
///
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 remote database with the selected database file.
///
private void Compare()
{
Task.Factory.StartNew(() =>
{
using (_notification.PushTaskItem("Comparing Databases..."))
{
try
{
if (_comparer != null)
{
_comparer.Dispose();
}
_remoteDB = RemoteDB.CreateDefault();
_localDB = new LocalDB(SlaveDBFile);
_comparer = new RemoteDBComparer(_remoteDB, _localDB, SelectedMachine.SerialNumber);
_comparer.Progress += Comparer_Progress;
_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.RemoteSQLiteFile = 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();
_remoteDB.SaveChanges();
_localDB.SaveChanges();
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--;
}
}
_remoteDB.SaveChanges();
_localDB.SaveChanges();
}
catch (DbEntityValidationException ex)
{
String message = "The following validation errors occurred while trying to update the database." + Environment.NewLine + Environment.NewLine;
foreach (var error in ex.EntityValidationErrors.SelectMany(x => x.ValidationErrors).ToList())
{
message += error.ErrorMessage + Environment.NewLine;
}
ShowError(message);
}
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 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));
}
///
/// Called when the application is shutting down.
///
///
public Task OnShutdownRequest()
{
if (_comparer != null)
{
_comparer.Dispose();
}
return Task.FromResult(true);
}
#endregion
}
}