public ExtractorProgress(bool isSlave = false)
 {
     _currentTable = new TableDef();
     _currentTask = new TableDef();
     _overallTimer = new StopWatch(false, false);
     _tableTimer = new StopWatch(false, false);
     _taskTimer = new StopWatch(false, false);
     _abort = false;
     IsSlave = isSlave;
     IsMigrating = false;
     Reset();
 }
        /// <summary>
        /// Extract data from the cart
        /// </summary>
        /// <param name="extractType"></param>
        /// <returns>true if successful</returns>
        public bool GetData(ExtractType extractType)
        {
            //choices are update only or full export
            //all normal exports include catalog and related files (exclusions, attNames, etc)
            //full export also includes all sales files (could be pulling from xml depending on the cart)
            //update will include the current sales month only if Rules.ExtractSalesUpdate is true for this cart

            if (Rules == null)
            {
                if (Log != null)
                    Log.WriteEntry(EventLogEntryType.Information, "Attempt to GetData with Rules null", "", Alias);
                return false;
            }
            IsExtracting = true;
            var dynamicUpdate = false;
            var totalTime = new StopWatch(true);
            var pullType = "new";

            //check migration status
            _migrationSlave =  Rules.MigrationRules != null && Rules.MigrationRules.Enabled
                                                    && !Rules.MigrationRules.IsMigrationMaster;
            if (_migrationSlave)
            {
                pullType = "Migration";
                Progress.IsSlave = true;
            }
            var result = String.Format("Pulling {0} data for {1} from {2}", pullType, Alias, Rules.CartName);
            var details = "";
            if (Log != null)
                Log.WriteEntry(EventLogEntryType.Information, result, "", Alias);
            Progress.Start(result);

            var catalogCount = 0;
            try
            {
                var generateTables = true;
                switch (extractType)
                {
                    case ExtractType.Full:
                        if (Rules.ExtractSalesFull) GetAllSales();
                        if (Rules.ExtractCustomerData) GetAllCustomers();
                        catalogCount = GetCatalog(true);
                        break;
                    case ExtractType.Update:
                        if (Rules.ExtractSalesUpdate) GetSalesUpdate();
                        if (Rules.ExtractCustomerData) GetCustomerUpdate();
                        catalogCount = GetCatalog();
                        break;
                    case ExtractType.Sales:
                        if (Rules.ExtractSalesFull || Rules.ExtractSalesFromXmlFile) GetAllSales();
                        else if (Rules.ExtractSalesUpdate) GetSalesUpdate();
                        else throw new Exception("Sales extraction is not supported for this site.");
                        break;
                    case ExtractType.Customers:
                        if (Rules.ExtractCustomerData) GetAllCustomers();
                        else throw new Exception("Customer extraction is not supported for this site.");
                        break;
                    case ExtractType.Inventory:
                        GetInventory();
                        dynamicUpdate = true;
                        generateTables = false; //inventory does not require generator
                        break;
                    case ExtractType.Catalog:
                        catalogCount = GetCatalog();
                        break;
            #if DEBUG
                    case ExtractType.Test:
                        RunTest();
                        break;
            #endif
                    case ExtractType.GenerateOnly:
                        break;
                }
                //check exclusion causes
                var exCauses = "";
                if (ExclusionStats != null && ExclusionStats.Any())
                {
                    //only save to rules when extraction is completed
                    Rules.ExclusionStats = new Dictionary<string,int>(ExclusionStats);

                    //exclusionStats.AddRange(dashSite.Rules.ExclusionStats.Select(c => new List<string> { c.Key, c.Value.ToString("N0") }));
                    exCauses = "\n\n" + ExclusionStats
                                                                .Aggregate("Exclusion Causes:", (a, b) => String.Format("{0}\n   {1} = {2}", a, b.Key, b.Value.ToString("N0")));

                    //check for excessive missing images
                    int causeCount;
                    if (Log != null && ExclusionStats.TryGetValue(MissingImageCause, out causeCount)
                        && catalogCount > 0 && ((float)causeCount / catalogCount) * 100F > Rules.MissingImageThreshold) //defaults to 10%
                        throw new Exception(string.Format("Error: {0} of {1} items are excluded due to missing images.",
                                                                                causeCount.ToString("N0"), catalogCount.ToString("N0")),
                                                                                new Exception(exCauses));
                }

                totalTime.Stop();
                if (dynamicUpdate)
                {
                    Rules.LastDynamicUpdateType = extractType;
                    Rules.LastDynamicUpdateTime = DateTime.Now;
                }
                else
                {
                    Rules.LastExtractionType = extractType;
                    Rules.LastExtractionTime = DateTime.Now;
                    Rules.LastExtractorDuration = (int)Math.Ceiling(totalTime.ElapsedMinutes);
                }
                if (!_migrationSlave)
                {
            #if !CART_EXTRACTOR_TEST_SITE
                    if (generateTables)
                    {
                        QueueGenerator();
                        result = string.Format("Successful update --pending Generator task{0}", exCauses);
                    }
                    else
            #endif
                        result = string.Format("Successful {0} update{1}", extractType, exCauses);
                }
                Progress.End(true, result);
                return true;
            }
            catch (ThreadAbortException)
            {
                result = "Update canceled by user";
                return false;
            }
            catch (Exception ex)
            {
                result = ex.Message;
                details = ex.InnerException == null ? "" : "Inner Exception: " + ex.InnerException.Message;
                if (Log != null)
                    Log.WriteEntry(EventLogEntryType.Information, result, details, Alias, true); //send support alert
                return false;
            }
            finally
            {
                if (!_migrationSlave)
                {
                    Rules.QueueSettings(false); //save the extraction time and duration
                    ReleaseGlobalData();
                    ReleaseCartData();
                }
                IsExtracting = false;
                if (Progress.Started) Progress.End(false, result);
                if (Log != null)
                {
                    Log.WriteEntry(EventLogEntryType.Information, Progress.Text, details, Alias);
                }
            }
        }