using System;
using System.Diagnostics;

namespace PerformanceCounters
{
    public class PerformanceCounterAverageTimer32 : IPerformanceCounter
    {
        private readonly PerformanceCounter _performanceCounter;
        private readonly PerformanceCounter _performanceCounterBase;
        private readonly PerformanceCounterManagement _performanceCounterManagement = new PerformanceCounterManagement();

        public PerformanceCounterAverageTimer32(string categoryName, string counterName, string instanceName, string categoryHelp = "", string counterHelp = "")
        {
            if (categoryName == null)
            {
                throw new ArgumentNullException("categoryName");
            }

            if (counterName == null)
            {
                throw new ArgumentNullException("counterName");
            }

            if (categoryHelp == null)
            {
                throw new ArgumentNullException("categoryHelp");
            }

            if (counterHelp == null)
            {
                throw new ArgumentNullException("counterHelp");
            }

            CreatePerformanceCounterCategory(categoryName, counterName, categoryHelp, counterHelp);

            _performanceCounter = _performanceCounterManagement.CreateOrGetPerformanceCounterInstance(categoryName, counterName, instanceName);
            _performanceCounterBase = _performanceCounterManagement.CreateOrGetPerformanceCounterInstance(categoryName, GetAverageBasePerformanceCounterName(counterName), instanceName);
        }

        public void Increment(long value)
        {
            Trace.TraceInformation(@"Incrementing performance counter instance \{0}({1})\{2}' by value {3}!", _performanceCounter.CategoryName, _performanceCounter.InstanceName, _performanceCounter.CounterName, value);
            _performanceCounter.IncrementBy(value);
            Trace.TraceInformation(@"Performance counter instance \{0}({1})\{2}' incremented by value {3}!", _performanceCounter.CategoryName, _performanceCounter.InstanceName, _performanceCounter.CounterName, value);
            _performanceCounterBase.Increment();
        }

        public void RemoveInstance()
        {
            Trace.TraceWarning(@"Removing performance counter instance \{0}({1})\{2}'!", _performanceCounter.CategoryName, _performanceCounter.InstanceName, _performanceCounter.CounterName);
            _performanceCounter.RemoveInstance();
            Trace.TraceWarning(@"Performance counter instance \{0}({1})\{2}' removed!", _performanceCounter.CategoryName, _performanceCounter.InstanceName, _performanceCounter.CounterName);

            Trace.TraceWarning(@"Removing performance counter instance \{0}({1})\{2}'!", _performanceCounterBase.CategoryName, _performanceCounterBase.InstanceName, _performanceCounterBase.CounterName);
            _performanceCounterBase.RemoveInstance();
            Trace.TraceWarning(@"Performance counter instance \{0}({1})\{2}' removed!", _performanceCounterBase.CategoryName, _performanceCounterBase.InstanceName, _performanceCounterBase.CounterName);
        }

        private string GetAverageBasePerformanceCounterName(string counterName)
        {
            return string.Format("{0} {1}", counterName, "base");
        }

        private void CreatePerformanceCounterCategory(string categoryName, string counterName, string categoryHelp = "", string performanceCounterHelperText = "")
        {
            string averageBasePerformanceCounterName = GetAverageBasePerformanceCounterName(counterName);

            if (!PerformanceCounterCategory.Exists(categoryName))
            {
                Trace.TraceInformation(@"Creating performance counter category '{0}', performance counter '\{0}(*)\{1}' and performance counter '\{0}(*)\{2}'", categoryName, counterName, averageBasePerformanceCounterName);

                var counters = new CounterCreationDataCollection
                {
                    new CounterCreationData(counterName, performanceCounterHelperText, PerformanceCounterType.AverageTimer32),
                    new CounterCreationData(averageBasePerformanceCounterName, string.Empty, PerformanceCounterType.AverageBase)
                };

                PerformanceCounterCategory.Create(categoryName, string.Empty, PerformanceCounterCategoryType.MultiInstance, counters);
                Trace.TraceInformation(@"Performance counter category '{0}', performance counter '\{0}(*)\{1}' and performance counter '\{0}(*)\{2}' created", categoryName, counterName, averageBasePerformanceCounterName);
            }

            Trace.TraceWarning(@"Performance counter category '{0}' already exists! Performance counter '\{0}(*)\{1}' and performance counter '\{0}(*)\{2}' will not be created!", categoryName, counterName, averageBasePerformanceCounterName);
        }
    }
}