2019-08-25 23:52:03 +00:00
using System ;
2019-07-22 22:17:46 +00:00
using System.Collections.Generic ;
using System.Collections.ObjectModel ;
2019-07-30 21:45:04 +00:00
using System.ComponentModel ;
2019-08-30 23:57:56 +00:00
using System.Diagnostics ;
2019-07-22 22:17:46 +00:00
using System.IO ;
2019-09-04 01:59:07 +00:00
using System.Linq ;
2019-07-22 22:17:46 +00:00
using System.Reflection ;
using System.Threading ;
2019-07-31 03:59:19 +00:00
using System.Windows ;
using System.Windows.Input ;
2019-07-22 22:17:46 +00:00
using System.Windows.Threading ;
using Wabbajack.Common ;
namespace Wabbajack
{
2019-07-30 21:45:04 +00:00
internal class AppState : INotifyPropertyChanged
2019-07-22 22:17:46 +00:00
{
public class CPUStatus
{
public int Progress { get ; internal set ; }
public string Msg { get ; internal set ; }
public int ID { get ; internal set ; }
}
public volatile bool Dirty ;
private Dispatcher dispatcher ;
2019-07-30 21:45:04 +00:00
public event PropertyChangedEventHandler PropertyChanged ;
public void OnPropertyChanged ( string name )
{
PropertyChanged ? . Invoke ( this , new PropertyChangedEventArgs ( name ) ) ;
}
2019-07-22 22:17:46 +00:00
public ObservableCollection < string > Log { get ; }
public ObservableCollection < CPUStatus > Status { get ; }
2019-07-30 21:45:04 +00:00
private string _mode ;
public string Mode
{
get
{
return _mode ;
}
set
{
_mode = value ;
OnPropertyChanged ( "Mode" ) ;
}
}
2019-08-07 23:06:38 +00:00
private bool _ignoreMissingFiles = false ;
public bool IgnoreMissingFiles
{
get
{
return _ignoreMissingFiles ;
}
set
{
if ( value )
{
if ( MessageBox . Show ( "Setting this value could result in broken installations. \n Are you sure you want to continue?" , "Ignore Missing Files?" , MessageBoxButton . OKCancel , MessageBoxImage . Warning )
= = MessageBoxResult . OK )
{
_ignoreMissingFiles = value ;
}
}
else
{
_ignoreMissingFiles = value ;
}
OnPropertyChanged ( "IgnoreMissingFiles" ) ;
}
}
2019-07-31 03:59:19 +00:00
private string _mo2Folder ;
2019-07-30 21:45:04 +00:00
private string _modListName ;
2019-07-31 03:59:19 +00:00
private ModList _modList ;
private string _location ;
2019-09-03 22:12:39 +00:00
private string _downloadLocation ;
2019-07-31 03:59:19 +00:00
2019-07-30 21:45:04 +00:00
public string ModListName
{
get
{
return _modListName ;
}
set
{
_modListName = value ;
OnPropertyChanged ( "ModListName" ) ;
}
}
2019-07-31 03:59:19 +00:00
public string Location
{
get
{
return _location ;
}
set
{
_location = value ;
OnPropertyChanged ( "Location" ) ;
}
}
2019-09-03 22:12:39 +00:00
public string DownloadLocation
{
get
{
return _downloadLocation ;
}
set
{
_downloadLocation = value ;
OnPropertyChanged ( "DownloadLocation" ) ;
}
}
2019-08-30 23:57:56 +00:00
private string _htmlReport ;
public Visibility ShowReportButton = > _htmlReport = = null ? Visibility . Collapsed : Visibility . Visible ;
public string HTMLReport
{
get { return _htmlReport ; }
set
{
_htmlReport = value ;
OnPropertyChanged ( "HTMLReport" ) ;
OnPropertyChanged ( "ShowReportButton" ) ;
}
}
2019-08-02 23:04:04 +00:00
private int _queueProgress ;
public int QueueProgress
{
get
{
return _queueProgress ;
}
set
{
if ( value ! = _queueProgress )
{
_queueProgress = value ;
OnPropertyChanged ( "QueueProgress" ) ;
}
}
}
2019-07-22 22:17:46 +00:00
private List < CPUStatus > InternalStatus { get ; }
public string LogFile { get ; private set ; }
public AppState ( Dispatcher d , String mode )
{
2019-09-04 01:43:16 +00:00
if ( Assembly . GetEntryAssembly ( ) . Location . ToLower ( ) . Contains ( "\\downloads\\" ) )
{
MessageBox . Show (
2019-09-04 01:59:07 +00:00
"This app seems to be running inside a folder called `Downloads`, such folders are often highly monitored by Antivirus software and they can often " +
2019-09-04 01:43:16 +00:00
"conflict with the operations Wabbajack needs to perform. Please move this executable outside of your `Downloads` folder and then restart the app." ,
"Cannot run inside `Downloads`" ,
MessageBoxButton . OK ,
MessageBoxImage . Error ) ;
Environment . Exit ( 1 ) ;
}
2019-08-20 21:44:32 +00:00
_startTime = DateTime . Now ;
2019-07-22 22:17:46 +00:00
LogFile = Assembly . GetExecutingAssembly ( ) . Location + ".log" ;
if ( LogFile . FileExists ( ) )
File . Delete ( LogFile ) ;
Mode = mode ;
Dirty = false ;
dispatcher = d ;
Log = new ObservableCollection < string > ( ) ;
Status = new ObservableCollection < CPUStatus > ( ) ;
InternalStatus = new List < CPUStatus > ( ) ;
var th = new Thread ( ( ) = > UpdateLoop ( ) ) ;
th . Priority = ThreadPriority . BelowNormal ;
th . IsBackground = true ;
th . Start ( ) ;
}
private void UpdateLoop ( )
{
while ( true )
{
if ( Dirty )
{
lock ( InternalStatus )
{
var data = InternalStatus . ToArray ( ) ;
dispatcher . Invoke ( ( ) = >
{
for ( int idx = 0 ; idx < data . Length ; idx + = 1 )
{
if ( idx > = Status . Count )
Status . Add ( data [ idx ] ) ;
else if ( Status [ idx ] ! = data [ idx ] )
Status [ idx ] = data [ idx ] ;
}
} ) ;
Dirty = false ;
}
}
2019-07-23 04:27:26 +00:00
Thread . Sleep ( 1000 ) ;
2019-07-22 22:17:46 +00:00
}
}
2019-07-31 03:59:19 +00:00
internal void ConfigureForInstall ( string modlist )
{
_modList = modlist . FromJSONString < ModList > ( ) ;
Mode = "Installing" ;
ModListName = _modList . Name ;
2019-08-30 23:57:56 +00:00
HTMLReport = _modList . ReportHTML ;
2019-07-31 03:59:19 +00:00
Location = Path . GetDirectoryName ( Assembly . GetExecutingAssembly ( ) . Location ) ;
}
2019-07-22 22:17:46 +00:00
public void LogMsg ( string msg )
{
2019-08-20 21:44:32 +00:00
msg = $"{(DateTime.Now - _startTime).TotalSeconds:0.##} - {msg}" ;
2019-07-22 22:17:46 +00:00
dispatcher . Invoke ( ( ) = > Log . Add ( msg ) ) ;
lock ( dispatcher ) {
File . AppendAllText ( LogFile , msg + "\r\n" ) ;
}
}
public void SetProgress ( int id , string msg , int progress )
{
lock ( InternalStatus )
{
Dirty = true ;
while ( id > = InternalStatus . Count )
{
InternalStatus . Add ( new CPUStatus ( ) ) ;
}
InternalStatus [ id ] = new CPUStatus ( ) { ID = id , Msg = msg , Progress = progress } ;
}
}
2019-07-31 03:59:19 +00:00
2019-08-02 23:04:04 +00:00
public void SetQueueSize ( int max , int current )
{
2019-08-22 22:05:16 +00:00
if ( max = = 0 )
max = 1 ;
2019-08-02 23:04:04 +00:00
var total = current * 100 / max ;
QueueProgress = total ;
}
2019-07-31 03:59:19 +00:00
private ICommand _changePath ;
public ICommand ChangePath
{
get
{
if ( _changePath = = null )
{
_changePath = new LambdaCommand ( ( ) = > true , ( ) = > this . ExecuteChangePath ( ) ) ;
}
return _changePath ;
}
}
2019-09-03 22:12:39 +00:00
private ICommand _changeDownloadPath ;
public ICommand ChangeDownloadPath
{
get
{
if ( _changeDownloadPath = = null )
{
_changeDownloadPath = new LambdaCommand ( ( ) = > true , ( ) = > this . ExecuteChangeDownloadPath ( ) ) ;
}
return _changeDownloadPath ;
}
}
2019-07-31 03:59:19 +00:00
private void ExecuteChangePath ( )
{
if ( Mode = = "Installing" )
{
var ofd = new Ookii . Dialogs . Wpf . VistaFolderBrowserDialog ( ) ;
ofd . Description = "Select Installation Directory" ;
ofd . UseDescriptionForTitle = true ;
if ( ofd . ShowDialog ( ) = = true )
{
Location = ofd . SelectedPath ;
}
}
else
{
var fsd = new Ookii . Dialogs . Wpf . VistaOpenFileDialog ( ) ;
fsd . Title = "Select a ModOrganizer modlist.txt file" ;
fsd . Filter = "modlist.txt|modlist.txt" ;
if ( fsd . ShowDialog ( ) = = true )
{
Location = fsd . FileName ;
ConfigureForBuild ( ) ;
}
}
}
2019-09-03 22:12:39 +00:00
private void ExecuteChangeDownloadPath ( )
{
var ofd = new Ookii . Dialogs . Wpf . VistaFolderBrowserDialog ( ) ;
ofd . Description = "Select a location for MO2 downloads" ;
ofd . UseDescriptionForTitle = true ;
if ( ofd . ShowDialog ( ) = = true )
{
DownloadLocation = ofd . SelectedPath ;
}
}
2019-07-31 03:59:19 +00:00
private void ConfigureForBuild ( )
{
var profile_folder = Path . GetDirectoryName ( Location ) ;
var mo2folder = Path . GetDirectoryName ( Path . GetDirectoryName ( profile_folder ) ) ;
if ( ! File . Exists ( Path . Combine ( mo2folder , "ModOrganizer.exe" ) ) )
LogMsg ( $"Error! No ModOrganizer2.exe found in {mo2folder}" ) ;
var profile_name = Path . GetFileName ( profile_folder ) ;
ModListName = profile_name ;
Mode = "Building" ;
2019-09-03 22:12:39 +00:00
var tmp_compiler = new Compiler ( mo2folder , Utils . Log ) ;
DownloadLocation = tmp_compiler . MO2DownloadsFolder ;
2019-07-31 03:59:19 +00:00
_mo2Folder = mo2folder ;
}
private ICommand _begin ;
2019-08-20 21:44:32 +00:00
private DateTime _startTime ;
2019-07-31 03:59:19 +00:00
public ICommand Begin
{
get
{
if ( _begin = = null )
{
_begin = new LambdaCommand ( ( ) = > true , ( ) = > this . ExecuteBegin ( ) ) ;
}
return _begin ;
}
}
2019-08-30 23:57:56 +00:00
private ICommand _showReportCommand ;
public ICommand ShowReportCommand
{
get
{
if ( _showReportCommand = = null )
{
_showReportCommand = new LambdaCommand ( ( ) = > true , ( ) = > this . ShowReport ( ) ) ;
}
return _showReportCommand ;
}
}
private void ShowReport ( )
{
var file = Path . GetTempFileName ( ) + ".html" ;
File . WriteAllText ( file , HTMLReport ) ;
Process . Start ( file ) ;
}
2019-07-31 03:59:19 +00:00
private void ExecuteBegin ( )
{
if ( Mode = = "Installing" )
{
var installer = new Installer ( _modList , Location , msg = > this . LogMsg ( msg ) ) ;
2019-08-07 23:06:38 +00:00
installer . IgnoreMissingFiles = IgnoreMissingFiles ;
2019-09-03 22:12:39 +00:00
installer . DownloadFolder = DownloadLocation ;
2019-07-31 03:59:19 +00:00
var th = new Thread ( ( ) = >
{
try
{
installer . Install ( ) ;
}
2019-08-02 22:31:13 +00:00
catch ( Exception ex )
{
2019-08-22 22:05:16 +00:00
while ( ex . InnerException ! = null ) ex = ex . InnerException ;
2019-08-07 23:06:38 +00:00
LogMsg ( ex . StackTrace ) ;
2019-08-22 23:29:44 +00:00
LogMsg ( ex . ToString ( ) ) ;
2019-08-02 22:31:13 +00:00
LogMsg ( $"{ex.Message} - Can't continue" ) ;
2019-07-31 03:59:19 +00:00
}
} ) ;
th . Priority = ThreadPriority . BelowNormal ;
th . Start ( ) ;
}
else
{
var compiler = new Compiler ( _mo2Folder , msg = > LogMsg ( msg ) ) ;
2019-08-07 23:06:38 +00:00
compiler . IgnoreMissingFiles = IgnoreMissingFiles ;
2019-07-31 03:59:19 +00:00
compiler . MO2Profile = ModListName ;
var th = new Thread ( ( ) = >
{
2019-08-07 23:06:38 +00:00
try
{
compiler . Compile ( ) ;
2019-08-30 23:57:56 +00:00
if ( compiler . ModList ! = null & & compiler . ModList . ReportHTML ! = null )
{
HTMLReport = compiler . ModList . ReportHTML ;
}
2019-08-07 23:06:38 +00:00
}
catch ( Exception ex )
{
2019-08-22 22:05:16 +00:00
while ( ex . InnerException ! = null ) ex = ex . InnerException ;
2019-08-07 23:06:38 +00:00
LogMsg ( ex . StackTrace ) ;
2019-08-22 23:29:44 +00:00
LogMsg ( ex . ToString ( ) ) ;
2019-08-07 23:06:38 +00:00
LogMsg ( $"{ex.Message} - Can't continue" ) ;
}
2019-07-31 03:59:19 +00:00
} ) ;
th . Priority = ThreadPriority . BelowNormal ;
th . Start ( ) ;
}
}
2019-07-22 22:17:46 +00:00
}
}