private void Contracts_Load(object sender, EventArgs e)
        {
            try
            {
                EMMADataSet.ContractTypeDataTable types = ContractTypes.GetAll();
                // Remove the 'Cargo' type.
                // This is used by the Delivery  planner and we don't want users either viewing
                // or creating that type of contract.
                /*DataRow[] cargoType = types.Select("ID = 3");
                if (cargoType != null && cargoType.Length > 0)
                {
                    types.RemoveContractTypeRow((EMMADataSet.ContractTypeRow)cargoType[0]);
                }*/
                cmbType.DisplayMember = "Description";
                cmbType.ValueMember = "ID";
                cmbType.DataSource = types;
                cmbType.SelectedValue = (short)ContractType.Courier;
                cmbType.SelectedIndexChanged += new EventHandler(cmbType_SelectedIndexChanged);

                _contracts = new ContractList();
                _contractsBindingSource = new BindingSource();
                _contractsBindingSource.DataSource = _contracts;

                DataGridViewCellStyle iskStyle = new DataGridViewCellStyle(RewardColumn.DefaultCellStyle);
                iskStyle.Format = IskAmount.FormatString();
                RewardColumn.DefaultCellStyle = iskStyle;
                CollateralColumn.DefaultCellStyle = iskStyle;
                ExpectedProfitColumn.DefaultCellStyle = iskStyle;

                contractsGrid.AutoGenerateColumns = false;
                contractsGrid.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.None;
                contractsGrid.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.None;

                contractsGrid.DataSource = _contractsBindingSource;
                ContractIDColumn.DataPropertyName = "ID";
                OwnerColumn.DataPropertyName = "Owner";
                IssueDateColumn.DataPropertyName = "IssueDate";
                PickupStationColumn.DataPropertyName = "PickupStation";
                DestinationStationColumn.DataPropertyName = "DestinationStation";
                RewardColumn.DataPropertyName = "Reward";
                CollateralColumn.DataPropertyName = "Collateral";
                ExpectedProfitColumn.DataPropertyName = "ExpectedProfit";
                StatusColumn.DataPropertyName = "Status";
                CompletedColumn.Image = icons.Images["tick.gif"];
                FailedColumn.Image = icons.Images["cross.gif"];
                ExpiredColumn.Image = icons.Images["expired.gif"];
                contractsGrid.CellClick += new DataGridViewCellEventHandler(contractsGrid_CellClick);
                contractsGrid.CellDoubleClick += new DataGridViewCellEventHandler(contractsGrid_CellDoubleClick);
                UserAccount.Settings.GetColumnWidths(this.Name, contractsGrid);

                List<CharCorpOption> charcorps = UserAccount.CurrentGroup.GetCharCorpOptions();
                _owners = new List<long>();
                foreach (CharCorpOption chop in charcorps)
                {
                    _owners.Add(chop.Corp ? chop.CharacterObj.CorpID : chop.CharacterObj.CharID);
                }
                cmbOwner.DisplayMember = "Name";
                cmbOwner.ValueMember = "Data";
                charcorps.Sort();
                cmbOwner.DataSource = charcorps;
                cmbOwner.SelectedValue = 0;
                cmbOwner.Enabled = false;
                cmbOwner.SelectedIndexChanged += new EventHandler(cmbOwner_SelectedIndexChanged);
                chkIngoreOwner.Checked = true;
                chkIngoreOwner.CheckedChanged += new EventHandler(chkIngoreOwner_CheckedChanged);

                _recentStations = UserAccount.CurrentGroup.Settings.RecentStations;
                _recentStations.Sort();
                cmbDestination.Tag = 0;
                cmbDestination.Items.AddRange(_recentStations.ToArray());
                cmbDestination.AutoCompleteSource = AutoCompleteSource.ListItems;
                cmbDestination.AutoCompleteMode = AutoCompleteMode.Suggest;
                cmbDestination.KeyDown += new KeyEventHandler(cmbDestination_KeyDown);
                cmbDestination.SelectedIndexChanged += new EventHandler(cmbDestination_SelectedIndexChanged);

                cmbPickup.Tag = 0;
                cmbPickup.Items.AddRange(_recentStations.ToArray());
                cmbPickup.AutoCompleteSource = AutoCompleteSource.ListItems;
                cmbPickup.AutoCompleteMode = AutoCompleteMode.Suggest;
                cmbPickup.KeyDown += new KeyEventHandler(cmbPickup_KeyDown);
                cmbPickup.SelectedIndexChanged += new EventHandler(cmbPickup_SelectedIndexChanged);

                EMMADataSet.ContractStatesDataTable states = ContractStatus.GetAll();
                BindingSource statusSource = new BindingSource();
                statusSource.DataSource = states;
                statusSource.Sort = "Description";
                cmbStatus.DisplayMember = "Description";
                cmbStatus.ValueMember = "ID";
                cmbStatus.DataSource = statusSource;
                cmbStatus.SelectedValue = 1;
                cmbStatus.SelectedIndexChanged += new EventHandler(cmbStatus_SelectedIndexChanged);

                this.FormClosing += new FormClosingEventHandler(ViewContracts_FormClosing);
                RefreshGUI();
                DisplayContracts();
            }
            catch (Exception ex)
            {
                // Creating new EMMAexception will cause error to be logged.
                EMMAException emmaex = ex as EMMAException;
                if (emmaex == null)
                {
                    emmaex = new EMMAException(ExceptionSeverity.Critical, "Error setting up contracts form", ex);
                }
                MessageBox.Show("Problem setting up contracts view.\r\nCheck " + Globals.AppDataDir + "Logging\\ExceptionLog.txt" +
                    " for details.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        private void RefreshList()
        {
            List<long> ownerIDs = new List<long>();
            long pickupStation = 0, destinationStation = 0;
            short status = 0;
            ContractType type = ContractType.Any;

            if(cmbType.SelectedValue != null)
            {
                type = (ContractType)cmbType.SelectedValue;
            }
            if (cmbOwner.SelectedValue != null && !chkIngoreOwner.Checked)
            {
                CharCorp data = (CharCorp)cmbOwner.SelectedValue;
                ownerIDs.Add(data.corp ? data.characterObj.CorpID : data.characterObj.CharID);
            }
            if (ownerIDs.Count == 0)
            {
                ownerIDs = _owners;
            }

            pickupStation = long.Parse(cmbPickup.Tag.ToString());
            destinationStation = long.Parse(cmbDestination.Tag.ToString());
            if (cmbStatus.SelectedValue != null) { status = (short)cmbStatus.SelectedValue; }

            CompletedColumn.Visible = (type == ContractType.Courier && status == 1);
            ExpiredColumn.Visible = (type == ContractType.Courier && status == 1);
            FailedColumn.Visible = (type == ContractType.Courier && status == 1);
            DestinationStationColumn.Visible = type == ContractType.Courier;
            StatusColumn.Visible = type == ContractType.Courier;
            RewardColumn.Visible = type == ContractType.Courier;
            ExpectedProfitColumn.Visible = type == ContractType.Courier;
            PickupStationColumn.HeaderText = type == ContractType.Courier ? "Pickup Station" : "Station";
            CollateralColumn.HeaderText = type == ContractType.Courier ? "Collateral" : "Price";

            //ListSortDirection sortDirection = ListSortDirection.Descending;
            //DataGridViewColumn sortColumn = contractsGrid.SortedColumn;
            //if (contractsGrid.SortOrder == SortOrder.Ascending) sortDirection = ListSortDirection.Ascending;
            List<SortInfo> sortinfo = contractsGrid.GridSortInfo;

            _contracts = Contracts.GetContracts(ownerIDs, status, pickupStation, destinationStation, type);
            _contractsBindingSource.DataSource = _contracts;

            //if (sortColumn != null)
            //{
            //    contractsGrid.Sort(sortColumn, sortDirection);
            //}
            //else
            //{
            //    contractsGrid.Sort(IssueDateColumn, ListSortDirection.Descending);
            //}
            if (sortinfo.Count == 0)
            {
                DataGridViewColumn column = contractsGrid.Columns["IssueDateColumn"];
                sortinfo.Add(new SortInfo(column.Index, column.DataPropertyName));
            }
            contractsGrid.GridSortInfo = sortinfo;

            Text = "Viewing " + _contractsBindingSource.Count + " contracts";
        }
 private void AutoCon(object ownerID)
 {
     long id = (long)ownerID;
     _contracts = _autocon.GenerateContracts(id);
 }
 public static ContractList GetContracts(List<long> ownerIDs, short status, long pickupStationID,
     long destinationStationID, ContractType contractType)
 {
     ContractList retVal = new ContractList();
     EMMADataSet.ContractsDataTable table = new EMMADataSet.ContractsDataTable();
     StringBuilder ownerIDString = new StringBuilder("");
     foreach (long ownerID in ownerIDs)
     {
         if (ownerIDString.Length != 0) { ownerIDString.Append(","); }
         ownerIDString.Append(ownerID);
     }
     contractsTableAdapter.FillByAny(table, ownerIDString.ToString(), pickupStationID,
         destinationStationID, status, (short)contractType);
     foreach (EMMADataSet.ContractsRow contract in table)
     {
         retVal.Add(new Contract(contract));
     }
     return retVal;
 }
        public ContractList GenerateContracts(long assetOwnerID)
        {
            ContractList retVal = new ContractList();

            try
            {
                Diagnostics.ResetAllTimers();
                //bool corp = false;
                //APICharacter character = UserAccount.CurrentGroup.GetCharacter(assetOwnerID, ref corp);

                // Get a list of assets for this char/corp that are enabled for auto contracting.
                // the list is sorted by locationID
                bool exclude = UserAccount.CurrentGroup.Settings.AutoCon_ExcludeContainers;
                EMMADataSet.AssetsDataTable assets = Assets.GetAutoConAssets(assetOwnerID,
                    UserAccount.CurrentGroup.Settings.AutoCon_PickupLocations, exclude);
                long stationID = 0;
                decimal collateralTotal = 0;
                decimal volumeTotal = 0;
                int counter = 0;
                //long nextID = long.MaxValue;

                ItemValues itemValues = UserAccount.CurrentGroup.ItemValues;
                decimal collateralPerc = UserAccount.CurrentGroup.Settings.CollateralPercentage;
                decimal minCollateral = UserAccount.CurrentGroup.Settings.AutoCon_MinCollateral * 0.95m;
                decimal minReward = UserAccount.CurrentGroup.Settings.AutoCon_MinReward * 0.95m;
                decimal minVolume = UserAccount.CurrentGroup.Settings.AutoCon_MinVolume;
                long destination = UserAccount.CurrentGroup.Settings.AutoCon_DestiantionStation;

                Diagnostics.StartTimer("AutoConGenerate");
                Diagnostics.StartTimer("AutoConGenerate.Station");
                TimeSpan longest = new TimeSpan();
                string longestName = "";
                UpdateStatus(counter, assets.Count, "Processing Assets..", "", false);
                foreach (EMMADataSet.AssetsRow asset in assets)
                {
                    // Make sure we're dealing with assets inside a station.
                    if (asset.LocationID >= 60000000 && asset.LocationID < 70000000 &&
                        asset.LocationID != destination)
                    {
                        if (stationID != asset.LocationID && stationID != 0)
                        {
                            UpdateStatus(counter, assets.Count, "", Stations.GetStationName(asset.LocationID), false);
                            // When we get to the next station in the list, check if it will be
                            // excluded, then generate the contract if it wont be.
                            if (collateralTotal * (collateralPerc / 100) > minCollateral &&
                                collateralTotal * 0.1m > minReward &&
                                volumeTotal > minVolume)
                            {

                                DiagnosticUpdate("", "Station accepted");
                                DiagnosticUpdate("", "Approx collateral = " +
                                    (collateralTotal * (collateralPerc / 100)));
                                DiagnosticUpdate("", "Approx reward = " + (collateralTotal * 0.1m));
                                DiagnosticUpdate("", "Volume = " + volumeTotal);
                                ContractList newContracts = GenerateContracts(assetOwnerID, stationID, destination, true);
                                foreach (Contract newContract in newContracts)
                                {
                                    //newContract.ID = nextID;
                                    retVal.Add(newContract);
                                    //nextID--;
                                }
                            }
                            else
                            {
                                DiagnosticUpdate("", "Station rejected");
                                DiagnosticUpdate("", "Approx collateral = " +
                                    (collateralTotal * (collateralPerc / 100)));
                                DiagnosticUpdate("", "Approx reward = " + (collateralTotal * 0.1m));
                                DiagnosticUpdate("", "Volume = " + volumeTotal);
                            }
                            collateralTotal = 0;
                            volumeTotal = 0;
                            Diagnostics.StopTimer("AutoConGenerate.Station");
                            TimeSpan timetaken = Diagnostics.GetRunningTime("AutoConGenerate.Station");
                            DiagnosticUpdate("", "Total station time taken: " + timetaken.ToString());
                            if (timetaken.CompareTo(longest) > 0)
                            {
                                longest = timetaken;
                                longestName = Stations.GetStationName(stationID);
                            }
                            Diagnostics.ResetTimer("AutoConGenerate.Station");
                            Diagnostics.StartTimer("AutoConGenerate.Station");
                        }

                        // increase the rough totals counters for each asset at this station.
                        collateralTotal += itemValues.GetItemValue(asset.ItemID) * asset.Quantity;
                        volumeTotal += (decimal)(asset.Quantity * Items.GetItemVolume(asset.ItemID));
                        stationID = asset.LocationID;
                    }
                    counter++;
                    UpdateStatus(counter, assets.Count, "", "", false);
                }

                // Do this one last time for the final station...
                if (collateralTotal * (collateralPerc / 100) > minCollateral &&
                    collateralTotal * 0.1m > minReward &&
                    volumeTotal > minVolume)
                {
                    ContractList newContracts = GenerateContracts(assetOwnerID, stationID, destination, true);
                    foreach (Contract newContract in newContracts)
                    {
                        //newContract.ID = nextID;
                        retVal.Add(newContract);
                        //nextID--;
                    }
                }

                Diagnostics.StopTimer("AutoConGenerate");

                DiagnosticUpdate("", "Total time taken: " + Diagnostics.GetRunningTime("AutoConGenerate"));
                DiagnosticUpdate("", "Longest time taken: " + longestName + " " + longest.ToString());

                UpdateStatus(-1, -1, "Complete", "", true);
            }
            catch (ThreadAbortException)
            {
                // User has closed the progress dialog so just allow the execution to fall out of this loop.
            }
            catch (EMMAException)
            {
                // Occurs when an infinite loop is caught during execution, this will have already
                // generated a log entry and updated the user so just fall out of this method.
            }
            catch (Exception ex)
            {
                UpdateStatus(-1, -1, "Error", ex.Message, true);
                new EMMAException(ExceptionSeverity.Error, "Exception occured while running auto-contractor", ex);
            }

            return retVal;
        }
        public ContractList GenerateContracts(long ownerID, long pickupStation, long destinationStation, bool autoCon)
        {
            ContractList retVal = new ContractList();
            ContractItemList items = new ContractItemList();
            Dictionary<int, long> assetsUsed = new Dictionary<int, long>();
            decimal totVolume = 0, totCollateral = 0, totProfit = 0;
            ReportGroupSettings settings = UserAccount.CurrentGroup.Settings;
            decimal maxVolume = settings.AutoCon_MaxVolume;
            decimal maxCollateral = settings.AutoCon_MaxCollateral;
            bool allowStackSpliting = settings.AutoCon_AllowStackSplitting;
            string collateralBasedOn = settings.CollateralBasedOn;
            decimal collateralPerc = settings.CollateralPercentage;
            string rewardBasedOn = settings.RewardBasedOn;
            decimal minReward = settings.MinReward;
            decimal minRewardPerc = settings.MinRewardPercentage;
            decimal minAllowedCollateral = settings.AutoCon_MinCollateral;
            decimal minAllowedReward = settings.AutoCon_MinReward;
            decimal minAllowedVolume = settings.AutoCon_MinVolume;
            decimal maxReward = settings.MaxReward;
            decimal maxRewardPerc = settings.MaxRewardPercentage;
            decimal lowSecRewardBonus = settings.LowSecPickupBonusPerc;
            decimal rewardPerJump = settings.RewardPercPerJump;
            decimal rewardPerVol = settings.VolumeBasedRewardPerc;
            decimal flatRewardPerJump = settings.RewardPerJump;
            decimal flatRewardPerVol = settings.RewardPerVolume;
            decimal baseReward = settings.PickupReward;

            EveDataSet.mapSolarSystemsRow pickupSystemData = SolarSystems.GetSystem(
                Stations.GetStation(pickupStation).solarSystemID);

            int diag_contracts = 0;

            //bool corp = false;
            bool complete = true;
            bool relax = false;
            //APICharacter character = UserAccount.CurrentGroup.GetCharacter(ownerID, ref corp);
            // Get the list of assets available for auto-contracting at this station.
            Diagnostics.StartTimer("GenerateContract");
            Diagnostics.StartTimer("GenerateContract.Part1");
            EMMADataSet.AssetsDataTable assets = Assets.GetAutoConAssets(
                ownerID, pickupStation, true);
            Diagnostics.StopTimer("GenerateContract.Part1");
            int lastAssetCount = -1;

            // Had to remove this condition.
            // Consider the case where 9 mil units of trit are sat at a station.
            // Max volume limit is set to 30k m3 so the autocontractor wants to create
            // 3 contracts for 3 mil units each.
            // However, this condition will cause the system to drop into the infinite loop
            // diagnostics after the first contract.
            while (assets.Count > 0) // && lastAssetCount != assets.Count)
            {
                complete = true;
                relax = false;
                totVolume = 0;
                totProfit = 0;
                totCollateral = 0;
                assetsUsed = new Dictionary<int, long>();
                items = new ContractItemList();
                Contract contract = new Contract(ownerID, 5, pickupStation, destinationStation, 0,
                    0, 0, DateTime.UtcNow, new ContractItemList(), ContractType.Courier);
                lastAssetCount = assets.Count;

                foreach (EMMADataSet.AssetsRow asset in assets)
                {
                    decimal buyPrice = 0, sellPrice = 0, unitCollateral = 0;
                    int itemID = asset.ItemID;
                    decimal itemVolume = (decimal)Items.GetItemVolume(itemID);
                    long quantity = asset.Quantity;

                    // Check if we can use the full volume of these items without breaching the max volume
                    // limit.
                    if (autoCon && totVolume + (decimal)(quantity * itemVolume) > maxVolume &&
                        totVolume < maxVolume)
                    {
                        // Reduce the quantity of items being addded if they would exceed the
                        // volume limit
                        quantity = (int)Math.Round((maxVolume - totVolume) / (decimal)itemVolume,
                            0, MidpointRounding.AwayFromZero) - 1;
                        // This check will prevent infinite loops when the volume of a single item is greater
                        // than the max allowed contract volume.
                        if (maxVolume < itemVolume && totVolume == 0) { relax = true; quantity = 1; }
                        complete = false;
                    }
                    else if (totVolume >= maxVolume) { complete = false; }

                    Diagnostics.StartTimer("GenerateContract.Part2");
                    // Get estimated sell price for the items being added to the contract.
                    sellPrice = GetSellPrice(itemID, destinationStation);
                    Diagnostics.StopTimer("GenerateContract.Part2");
                    Diagnostics.StartTimer("GenerateContract.Part6");
                    // Get average buy price for the items being added to the contract.
                    buyPrice = GetBuyPrice(ownerID, itemID, pickupStation, quantity, asset.Quantity - quantity);
                    Diagnostics.StopTimer("GenerateContract.Part6");
                    Diagnostics.StartTimer("GenerateContract.Part3");
                    // calculate the collateral value of the items being added.
                    unitCollateral = CalcCollateral(collateralBasedOn, collateralPerc, buyPrice, sellPrice);

                    long lastQuantity = quantity;
                    while (autoCon && totCollateral + (unitCollateral * quantity) > maxCollateral && !relax &&
                        totCollateral < maxCollateral)
                    {
                        // Reduce the quantity of items being addded if they would exceed the
                        // collateral limit
                        quantity = (int)Math.Round((maxCollateral - totCollateral) / (decimal)unitCollateral,
                            MidpointRounding.AwayFromZero) - 1;
                        // This check will prevent infinite loops when the collateral for a single item is greater
                        // than the max allowed collateral.
                        if (maxCollateral < unitCollateral && totCollateral == 0) { relax = true; quantity = 1; }
                        complete = false;

                        // Catch a possible infinite loop.
                        if (lastQuantity == quantity) { relax = true; quantity = 1; }

                        lastQuantity = quantity;
                        // Recalculate buy price and collateral.
                        //buyPrice = GetBuyPrice(ownerID, itemID, pickupStation, quantity, asset.Quantity - quantity);
                        //unitCollateral = CalcCollateral(collateralBasedOn, collateralPerc, buyPrice, sellPrice);
                    }
                    if (totCollateral >= maxCollateral) { complete = false; }
                    Diagnostics.StopTimer("GenerateContract.Part3");

                    if ((quantity == asset.Quantity || allowStackSpliting || relax) && quantity > 0)
                    {
                        // Get up the values for the items being added and add them to the contract totals.
                        totVolume += (decimal)(quantity * itemVolume);
                        totCollateral += quantity * unitCollateral;
                        totProfit += quantity * sellPrice - quantity * buyPrice;
                        if (assetsUsed.ContainsKey(itemID))
                        {
                            // If we've already added an item with this id then just add the new quantity
                            // to the old contract item object...
                            assetsUsed[itemID] += quantity;
                            for (int i = 0; i < items.Count;i++ )
                            {
                                ContractItem itemData = items[i];
                                if (itemData.ItemID == itemID)
                                {
                                    itemData.Quantity += (int)quantity;
                                    i = items.Count;
                                }
                            }
                        }
                        else
                        {
                            // ...Otherwise create a new contract item and add it to the list.
                            assetsUsed.Add(itemID, quantity);
                            items.Add(new ContractItem(itemID, (int)quantity, sellPrice, buyPrice, contract));
                        }
                    }
                }

                Diagnostics.StartTimer("GenerateContract.Part4");
                // Get the distance between the pickup and destination stations
                int numJumps = SolarSystemDistances.GetDistanceBetweenStations(pickupStation, destinationStation);
                Diagnostics.StopTimer("GenerateContract.Part4");
                // Calculate the reward that will be given from completing the contract.
                decimal reward = CalcReward(rewardBasedOn, totCollateral, totProfit, minReward, maxReward,
                    minRewardPerc, maxRewardPerc, rewardPerJump, rewardPerVol, lowSecRewardBonus,
                    numJumps, totVolume, Stations.IsLowSec(pickupStation), flatRewardPerJump, flatRewardPerVol,
                    baseReward);

                contract.Items = items;
                contract.Reward = reward;
                contract.Collateral = totCollateral;
                contract.ExpectedProfit = totProfit;
                diag_contracts++;
                // Add the contract to the list
                if (!autoCon || (reward > minAllowedReward && totCollateral > minAllowedCollateral &&
                    totVolume > minAllowedVolume))
                {
                    retVal.Add(contract);
                }
                //else
                //{
                //    UpdateStatus(0, 0, "",
                //        "A contract (" + diag_contracts +  ") has been generated that does not meet the minimum " +
                //        "requirements." +
                //        (reward <= minAllowedReward ? " The reward (" + reward + ") is less than " +
                //        minAllowedReward + "." : "") +
                //        (totCollateral <= minAllowedCollateral ? " The collateral (" + totCollateral +
                //        ") is less than " + minAllowedCollateral + "." : "") +
                //        (totVolume <= minAllowedVolume ? " The volume (" + totVolume + ") is less than " +
                //        minAllowedVolume + "." : ""),
                //        false);
                //}

                Diagnostics.StartTimer("GenerateContract.Part5");
                if (!complete)
                {
                    // If we have not used all items at this location then
                    // remove the items  we have used from the list of current assets.
                    Dictionary<int, long>.Enumerator enumerator = assetsUsed.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        DataRow[] rows = assets.Select("ItemID = " + enumerator.Current.Key);
                        if (rows.Length > 0)
                        {
                            long q_remain = enumerator.Current.Value;
                            for (int i = 0; i < rows.Length; i++)
                            {
                                if (q_remain > 0)
                                {
                                    EMMADataSet.AssetsRow assetData = rows[i] as EMMADataSet.AssetsRow;
                                    long diff = q_remain - assetData.Quantity;
                                    if (diff >= 0)
                                    {
                                        q_remain -= assetData.Quantity;
                                        assets.RemoveAssetsRow(assetData);
                                    }
                                    else
                                    {
                                        assetData.Quantity -= (int)q_remain;
                                        q_remain = 0;
                                    }
                                }
                            }
                        }
                    }
                }
                else
                {
                    // otherwise, just clear the list of assets.
                    assets.Clear();
                }
                Diagnostics.StopTimer("GenerateContract.Part5");
            }

            #region Diagnostic dump if we've caught an infinite loop.
            if (assets.Count != 0)
            {
                UpdateStatus(0, 0, "Error: Infinite loop detected",
                    "Please send your 'logging/exceptionlog.txt' file to [email protected]. " +
                    "Warning, this file will contain information about your in-game assets.", true);
                StringBuilder errorText = new StringBuilder(
                    "Infinite loop detected during auto-contrator execution, diagnostics to follow:");
                errorText.Append("\r\n\t");
                errorText.Append("Assets Remaining:");
                foreach (EMMADataSet.AssetsRow asset in assets)
                {
                    errorText.Append("\r\n\t\t");
                    errorText.Append(Items.GetItemName(asset.ItemID).Replace(",", " "));
                    errorText.Append(",");
                    errorText.Append(asset.Quantity);
                    errorText.Append(",");
                    errorText.Append(Items.GetItemVolume(asset.ItemID));
                }
                errorText.Append("\r\n\t");
                errorText.Append("Contracts created:");
                if (retVal.Count == 0) { errorText.Append("\r\n\t\t"); errorText.Append("NONE"); }
                foreach (Contract contract in retVal)
                {
                    errorText.Append("\r\n\t\t");
                    errorText.Append("ID: ");
                    errorText.Append(contract.ID);
                    errorText.Append("\r\n\t\t\t");
                    errorText.Append("Collateral: ");
                    errorText.Append(contract.Collateral);
                    errorText.Append("\r\n\t\t\t");
                    errorText.Append("Reward: ");
                    errorText.Append(contract.Reward);
                    errorText.Append("\r\n\t\t\t");
                    errorText.Append("Total Volume: ");
                    errorText.Append(contract.TotalVolume);
                    errorText.Append("\r\n\t\t\t");
                    errorText.Append("Profit: ");
                    errorText.Append(contract.ExpectedProfit);
                    errorText.Append("\r\n\t\t\t");
                    errorText.Append("Contract Items:");
                    foreach (ContractItem item in contract.Items)
                    {
                        errorText.Append("\r\n\t\t\t\t");
                        errorText.Append(item.Item);
                        errorText.Append(",");
                        errorText.Append(item.Quantity);
                        errorText.Append(",");
                        errorText.Append(item.ItemVolume);
                    }
                }
                errorText.Append("\r\n\t");
                errorText.Append("Max Volume: ");
                errorText.Append(maxVolume);
                errorText.Append("\r\n\t");
                errorText.Append("Max Collateral: ");
                errorText.Append(maxCollateral);
                errorText.Append("\r\n\t");
                errorText.Append("Max Reward: ");
                errorText.Append(maxReward);
                errorText.Append("\r\n\t");
                errorText.Append("Max Reward Percentage: ");
                errorText.Append(maxRewardPerc);
                errorText.Append("\r\n\t");
                errorText.Append("Min Allowed Collateral: ");
                errorText.Append(minAllowedCollateral);
                errorText.Append("\r\n\t");
                errorText.Append("Min Allowed Reward: ");
                errorText.Append(minAllowedReward);
                errorText.Append("\r\n\t");
                errorText.Append("Min Allowed Volume: ");
                errorText.Append(minAllowedVolume);
                errorText.Append("\r\n\t");
                errorText.Append("Min Reward: ");
                errorText.Append(minReward);
                errorText.Append("\r\n\t");
                errorText.Append("Min Reward Percentage: ");
                errorText.Append(minRewardPerc);
                errorText.Append("\r\n\t");
                errorText.Append("Allow stack splitting: ");
                errorText.Append(allowStackSpliting);

                throw new EMMAException(ExceptionSeverity.Error, errorText.ToString());
            }
            #endregion

            DiagnosticUpdate("", "Complete time: " + Diagnostics.GetRunningTime("GenerateContract").ToString());
            DiagnosticUpdate("", "Time loading assets: " +
                Diagnostics.GetRunningTime("GenerateContract.Part1").ToString());
            DiagnosticUpdate("", "Get item sell prices: " +
                Diagnostics.GetRunningTime("GenerateContract.Part2").ToString());
            DiagnosticUpdate("", "Get item buy prices: " +
                Diagnostics.GetRunningTime("GenerateContract.Part6").ToString());
            DiagnosticUpdate("", "Calc and restrict collateral: " +
                Diagnostics.GetRunningTime("GenerateContract.Part3").ToString());
            DiagnosticUpdate("", "Get route length: " +
                Diagnostics.GetRunningTime("GenerateContract.Part4").ToString());
            DiagnosticUpdate("", "Remove used assets: " +
                Diagnostics.GetRunningTime("GenerateContract.Part5").ToString());
            DiagnosticUpdate("", "Total contracts generated: " + diag_contracts);

            return retVal;
            }
        private XmlNode AddContractsToXML(XmlDocument xml, ContractList contracts)
        {
            XmlNode rowSet = NewContractRowset(xml);

            foreach (Contract contract in contracts)
            {
                //XmlNode node = AddContractRow(xml, contract);
                //rowSet.AppendChild(node);
            }

            return rowSet;
        }