<commit_before>﻿// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace RGB.NET.Core
{
    /// <summary>
    /// Represents a RGB-surface containing multiple devices.
    /// </summary>
    public partial class RGBSurface : AbstractBindable
    {
        #region Properties & Fields

        /// <summary>
        /// Gets the singelot-instance of the <see cref="RGBSurface"/> class.
        /// </summary>
        public static RGBSurface Instance { get; } = new RGBSurface();

        private DateTime _lastUpdate;

        private IList<IRGBDeviceProvider> _deviceProvider = new List<IRGBDeviceProvider>();
        private IList<IRGBDevice> _devices = new List<IRGBDevice>();

        // ReSharper disable InconsistentNaming

        private readonly LinkedList<ILedGroup> _ledGroups = new LinkedList<ILedGroup>();

        private readonly Rectangle _surfaceRectangle = new Rectangle();

        // ReSharper restore InconsistentNaming

        /// <summary>
        /// Gets a readonly list containing all loaded <see cref="IRGBDevice"/>.
        /// </summary>
        public IEnumerable<IRGBDevice> Devices => new ReadOnlyCollection<IRGBDevice>(_devices);

        /// <summary>
        /// Gets a copy of the <see cref="Rectangle"/> representing this <see cref="RGBSurface"/>.
        /// </summary>
        public Rectangle SurfaceRectangle => new Rectangle(_surfaceRectangle);

        /// <summary>
        /// Gets a list of all <see cref="Led"/> on this <see cref="RGBSurface"/>.
        /// </summary>
        public IEnumerable<Led> Leds => _devices.SelectMany(x => x);

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="RGBSurface"/> class.
        /// </summary>
        private RGBSurface()
        {
            _lastUpdate = DateTime.Now;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Perform an update for all dirty <see cref="Led"/>, or all <see cref="Led"/>, if flushLeds is set to true.
        /// </summary>
        /// <param name="flushLeds">Specifies whether all <see cref="Led"/>, (including clean ones) should be updated.</param>
        public void Update(bool flushLeds = false)
        {
            OnUpdating();

            lock (_ledGroups)
            {
                // Update effects
                foreach (ILedGroup ledGroup in _ledGroups)
                    ledGroup.UpdateEffects();

                // Render brushes
                foreach (ILedGroup ledGroup in _ledGroups.OrderBy(x => x.ZIndex))
                    Render(ledGroup);
            }

            foreach (IRGBDevice device in Devices)
                device.Update(flushLeds);

            OnUpdated();
        }

        /// <summary>
        /// Renders a ledgroup.
        /// </summary>
        /// <param name="ledGroup">The led group to render.</param>
        private void Render(ILedGroup ledGroup)
        {
            IList<Led> leds = ledGroup.GetLeds().ToList();
            IBrush brush = ledGroup.Brush;

            if ((brush == null) || !brush.IsEnabled) return;

            try
            {
                switch (brush.BrushCalculationMode)
                {
                    case BrushCalculationMode.Relative:
                        Rectangle brushRectangle = new Rectangle(leds.Select(x => GetDeviceLedLocation(x)));
                        Point offset = new Point(-brushRectangle.Location.X, -brushRectangle.Location.Y);
                        brushRectangle.Location.X = 0;
                        brushRectangle.Location.Y = 0;
                        brush.PerformRender(brushRectangle,
                                            leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x, offset))));
                        break;
                    case BrushCalculationMode.Absolute:
                        brush.PerformRender(SurfaceRectangle, leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x))));
                        break;
                    default:
                        throw new ArgumentException();
                }

                brush.UpdateEffects();
                brush.PerformFinalize();

                foreach (KeyValuePair<BrushRenderTarget, Color> renders in brush.RenderedTargets)
                    renders.Key.Led.Color = renders.Value;
            }
            // ReSharper disable once CatchAllClause
            catch (Exception ex)
            {
                OnException(ex);
            }
        }

        private Rectangle GetDeviceLedLocation(Led led, Point extraOffset = null)
        {
            return extraOffset != null
                       ? new Rectangle(led.LedRectangle.Location + led.Device.Location + extraOffset, led.LedRectangle.Size)
                       : new Rectangle(led.LedRectangle.Location + led.Device.Location, led.LedRectangle.Size);
        }

        /// <summary>
        /// Attaches the given <see cref="ILedGroup"/>.
        /// </summary>
        /// <param name="ledGroup">The <see cref="ILedGroup"/> to attach.</param>
        /// <returns><c>true</c> if the <see cref="ILedGroup"/> could be attached; otherwise, <c>false</c>.</returns>
        public bool AttachLedGroup(ILedGroup ledGroup)
        {
            if (ledGroup == null) return false;

            lock (_ledGroups)
            {
                if (_ledGroups.Contains(ledGroup)) return false;

                _ledGroups.AddLast(ledGroup);
                ledGroup.OnAttach();

                return true;
            }
        }

        /// <summary>
        /// Detaches the given <see cref="ILedGroup"/>.<commit_msg>Fixed wrong exception-handling<commit_after>﻿// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable UnusedMember.Global

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;

namespace RGB.NET.Core
{
    /// <summary>
    /// Represents a RGB-surface containing multiple devices.
    /// </summary>
    public partial class RGBSurface : AbstractBindable
    {
        #region Properties & Fields

        /// <summary>
        /// Gets the singelot-instance of the <see cref="RGBSurface"/> class.
        /// </summary>
        public static RGBSurface Instance { get; } = new RGBSurface();

        private DateTime _lastUpdate;

        private IList<IRGBDeviceProvider> _deviceProvider = new List<IRGBDeviceProvider>();
        private IList<IRGBDevice> _devices = new List<IRGBDevice>();

        // ReSharper disable InconsistentNaming

        private readonly LinkedList<ILedGroup> _ledGroups = new LinkedList<ILedGroup>();

        private readonly Rectangle _surfaceRectangle = new Rectangle();

        // ReSharper restore InconsistentNaming

        /// <summary>
        /// Gets a readonly list containing all loaded <see cref="IRGBDevice"/>.
        /// </summary>
        public IEnumerable<IRGBDevice> Devices => new ReadOnlyCollection<IRGBDevice>(_devices);

        /// <summary>
        /// Gets a copy of the <see cref="Rectangle"/> representing this <see cref="RGBSurface"/>.
        /// </summary>
        public Rectangle SurfaceRectangle => new Rectangle(_surfaceRectangle);

        /// <summary>
        /// Gets a list of all <see cref="Led"/> on this <see cref="RGBSurface"/>.
        /// </summary>
        public IEnumerable<Led> Leds => _devices.SelectMany(x => x);

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="RGBSurface"/> class.
        /// </summary>
        private RGBSurface()
        {
            _lastUpdate = DateTime.Now;
        }

        #endregion

        #region Methods

        /// <summary>
        /// Perform an update for all dirty <see cref="Led"/>, or all <see cref="Led"/>, if flushLeds is set to true.
        /// </summary>
        /// <param name="flushLeds">Specifies whether all <see cref="Led"/>, (including clean ones) should be updated.</param>
        public void Update(bool flushLeds = false)
        {
            try
            {
                OnUpdating();

                lock (_ledGroups)
                {
                    // Update effects
                    foreach (ILedGroup ledGroup in _ledGroups)
                        try { ledGroup.UpdateEffects(); }
                        catch (Exception ex) { OnException(ex); }

                    // Render brushes
                    foreach (ILedGroup ledGroup in _ledGroups.OrderBy(x => x.ZIndex))
                        try { Render(ledGroup); }
                        catch (Exception ex) { OnException(ex); }
                }

                foreach (IRGBDevice device in Devices)
                    try { device.Update(flushLeds); }
                    catch (Exception ex) { OnException(ex); }

                OnUpdated();
            }
            catch (Exception ex)
            {
                OnException(ex);
            }
        }

        /// <summary>
        /// Renders a ledgroup.
        /// </summary>
        /// <param name="ledGroup">The led group to render.</param>
        private void Render(ILedGroup ledGroup)
        {
            IList<Led> leds = ledGroup.GetLeds().ToList();
            IBrush brush = ledGroup.Brush;

            if ((brush == null) || !brush.IsEnabled) return;

            switch (brush.BrushCalculationMode)
            {
                case BrushCalculationMode.Relative:
                    Rectangle brushRectangle = new Rectangle(leds.Select(x => GetDeviceLedLocation(x)));
                    Point offset = new Point(-brushRectangle.Location.X, -brushRectangle.Location.Y);
                    brushRectangle.Location.X = 0;
                    brushRectangle.Location.Y = 0;
                    brush.PerformRender(brushRectangle,
                                        leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x, offset))));
                    break;
                case BrushCalculationMode.Absolute:
                    brush.PerformRender(SurfaceRectangle, leds.Select(x => new BrushRenderTarget(x, GetDeviceLedLocation(x))));
                    break;
                default:
                    throw new ArgumentException();
            }

            brush.UpdateEffects();
            brush.PerformFinalize();

            foreach (KeyValuePair<BrushRenderTarget, Color> renders in brush.RenderedTargets)
                renders.Key.Led.Color = renders.Value;
        }

        private Rectangle GetDeviceLedLocation(Led led, Point extraOffset = null)
        {
            return extraOffset != null
                       ? new Rectangle(led.LedRectangle.Location + led.Device.Location + extraOffset, led.LedRectangle.Size)
                       : new Rectangle(led.LedRectangle.Location + led.Device.Location, led.LedRectangle.Size);
        }

        /// <summary>
        /// Attaches the given <see cref="ILedGroup"/>.
        /// </summary>
        /// <param name="ledGroup">The <see cref="ILedGroup"/> to attach.</param>
        /// <returns><c>true</c> if the <see cref="ILedGroup"/> could be attached; otherwise, <c>false</c>.</returns>
        public bool AttachLedGroup(ILedGroup ledGroup)
        {
            if (ledGroup == null) return false;

            lock (_ledGroups)
            {
                if (_ledGroups.Contains(ledGroup)) return false;

                _ledGroups.AddLast(ledGroup);
                ledGroup.OnAttach();

                return true;
            }
        }

        /// <summary>
        /// Detaches the given <see cref="ILedGroup"/>.
{'fraction_non_alphanumeric': 0.10887233322045378, 'fraction_numerical': 0.0003386386725364037, 'mean_word_length': 1.693342453260374, 'pattern_counts': {'":': 0, '<': 115, '<?xml version=': 0, '>': 131, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1973211', 'n_tokens_mistral': 3116, 'n_tokens_neox': 2953, 'n_words': 746}