private void AddLocalMinerStatistics(List<MiningStatistics> statisticsList)
        {
            //call ToList() so we can get a copy - otherwise risk:
            //System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
            List<MinerProcess> minerProcesses = MiningEngine.MinerProcesses.ToList();

            foreach (MinerProcess minerProcess in minerProcesses)
            {
                List<DeviceInformation> deviceInformationList = GetDeviceInfoFromProcess(minerProcess);

                if (deviceInformationList == null) //handled failure getting API info
                    continue;

                //starting with bfgminer 3.7 we need the DEVDETAILS response to tie things from DEVS up with -d? details
                List<DeviceDetails> processDevices = GetProcessDeviceDetails(minerProcess, deviceInformationList);

                if (processDevices == null) //handled failure getting API info
                    continue;

                foreach (DeviceInformation deviceInformation in deviceInformationList)
                {
                    MiningStatistics miningStatistics = new MiningStatistics { MachineName = Environment.MachineName };
                    PopulateMobileMinerStatistics(miningStatistics, deviceInformation, GetCoinNameForApiContext(minerProcess.ApiContext));

                    DeviceDetails deviceDetails = processDevices.SingleOrDefault(d => d.Name.Equals(deviceInformation.Name, StringComparison.OrdinalIgnoreCase)
                        && (d.ID == deviceInformation.ID));
                    int deviceIndex = GetDeviceIndexForDeviceDetails(deviceDetails, minerProcess);
                    Device device = Devices[deviceIndex];
                    Coin coinConfiguration = CoinConfigurationForDevice(device);

                    miningStatistics.FullName = GetFriendlyDeviceName(device);

                    miningStatistics.PoolName = GetPoolNameByIndex(coinConfiguration, deviceInformation.PoolIndex).DomainFromHost();

                    statisticsList.Add(miningStatistics);
                }
            }
        }
        private void PopulateMobileMinerStatistics(MiningStatistics miningStatistics, DeviceInformation deviceInformation,
            string coinName)
        {
            miningStatistics.MinerName = "MultiMiner";
            miningStatistics.CoinName = coinName;
            Coin coinConfiguration = EngineConfiguration.CoinConfigurations.Single(c => c.PoolGroup.Name.Equals(coinName));
            PoolGroup coin = coinConfiguration.PoolGroup;

            //don't send non-coin Ids to MobileMiner
            if (coin.Kind != PoolGroup.PoolGroupKind.MultiCoin)
                miningStatistics.CoinSymbol = coin.Id;

            CoinAlgorithm algorithm = MinerFactory.Instance.GetAlgorithm(coin.Algorithm);

            //MobileMiner currently only supports SHA and Scrypt
            //attempt to treat them as "Families" for now
            if ((algorithm.Family == CoinAlgorithm.AlgorithmFamily.SHA2) ||
                (algorithm.Family == CoinAlgorithm.AlgorithmFamily.SHA3))
                //SHA family algorithms grouped together
                miningStatistics.Algorithm = AlgorithmFullNames.SHA256;
            else
                //assume Scrypt for rest until MobileMiner supports more
                miningStatistics.Algorithm = AlgorithmFullNames.Scrypt;

            miningStatistics.PopulateFrom(deviceInformation);
        }
        private void AddNetworkMinerStatistics(NetworkDevices.NetworkDevice networkDevice, List<MiningStatistics> statisticsList)
        {
            List<DeviceInformation> deviceInformationList = GetDeviceInfoFromAddress(networkDevice.IPAddress, networkDevice.Port);

            if (deviceInformationList == null) //handled failure getting API info
                return;

            List<PoolInformation> poolInformationList = GetCachedPoolInfoFromAddress(networkDevice.IPAddress, networkDevice.Port);

            VersionInformation versionInformation = GetVersionInfoFromAddress(networkDevice.IPAddress, networkDevice.Port);

            //we cannot continue without versionInformation as the MinerName is required by MobileMiner or it returns HTTP 400
            if (versionInformation == null) //handled failure getting API info
                return;

            foreach (DeviceInformation deviceInformation in deviceInformationList)
            {
                string devicePath = String.Format("{0}:{1}", networkDevice.IPAddress, networkDevice.Port);

                //don't submit stats until we have a valid ViewModel for the Network Device
                DeviceViewModel deviceViewModel = LocalViewModel.Devices.SingleOrDefault(d => d.Path.Equals(devicePath));
                if (deviceViewModel == null)
                    continue;

                MiningStatistics miningStatistics = new MiningStatistics
                {
                    // submit the Friendly device / machine name
                    MachineName = LocalViewModel.GetFriendlyDeviceName(devicePath, devicePath),

                    // versionInformation may be null if the read timed out
                    MinerName = versionInformation.Name,
                    CoinName = Engine.Data.KnownCoins.BitcoinName,
                    CoinSymbol = Engine.Data.KnownCoins.BitcoinSymbol,
                    Algorithm = AlgorithmFullNames.SHA256,
                    Appliance = true
                };

                miningStatistics.PopulateFrom(deviceInformation);

                //ensure poolIndex is valid for poolInformationList
                //user(s) reported index errors so we can't out on the RPC API here
                //https://github.com/nwoolls/MultiMiner/issues/64
                if ((deviceInformation.PoolIndex >= 0) &&
                    // poolInformationList may be null if an RPC API call timed out
                    (poolInformationList != null) &&
                    (deviceInformation.PoolIndex < poolInformationList.Count))
                {
                    string poolUrl = poolInformationList[deviceInformation.PoolIndex].Url;
                    miningStatistics.PoolName = poolUrl.DomainFromHost();

                    Coin coinConfiguration = CoinConfigurationForPoolUrl(poolUrl);
                    if (coinConfiguration != null)
                    {
                        miningStatistics.CoinName = coinConfiguration.PoolGroup.Name;
                        miningStatistics.CoinSymbol = coinConfiguration.PoolGroup.Id;
                        CoinAlgorithm algorithm = MinerFactory.Instance.GetAlgorithm(coinConfiguration.PoolGroup.Algorithm);

                        //MobileMiner is only SHA & Scrypt for now
                        if ((algorithm.Family == CoinAlgorithm.AlgorithmFamily.SHA2) ||
                            (algorithm.Family == CoinAlgorithm.AlgorithmFamily.SHA3))
                            miningStatistics.Algorithm = AlgorithmFullNames.SHA256;
                        else
                            miningStatistics.Algorithm = AlgorithmFullNames.Scrypt;
                    }
                }

                statisticsList.Add(miningStatistics);
            }
        }