namespace CommonLibrary
{
    using System;
    using System.Diagnostics;

    public class SystemInfo
    {
        private static readonly object LockHelper = new object();

        private static SystemInfo sysinfo;

        private PerformanceCounter cpuProcessorTime = new PerformanceCounter("Processor", "% Processor Time", "_Total");
        private PerformanceCounter cpuPrivilegedTime = new PerformanceCounter("Processor", "% Privileged Time", "_Total");
        private PerformanceCounter cpuInterruptTime = new PerformanceCounter("Processor", "% Interrupt Time", "_Total");
        private PerformanceCounter cpuDPCTime = new PerformanceCounter("Processor", "% DPC Time", "_Total");
        private PerformanceCounter memAvailable = new PerformanceCounter("Memory", "Available MBytes", null);
        private PerformanceCounter memCommited = new PerformanceCounter("Memory", "Committed Bytes", null);
        private PerformanceCounter memCommitLimit = new PerformanceCounter("Memory", "Commit Limit", null);
        private PerformanceCounter memCommitedPerc = new PerformanceCounter("Memory", "% Committed Bytes In Use", null);
        private PerformanceCounter memPollPaged = new PerformanceCounter("Memory", "Pool Paged Bytes", null);
        private PerformanceCounter memPollNonPaged = new PerformanceCounter("Memory", "Pool Nonpaged Bytes", null);
        private PerformanceCounter memCached = new PerformanceCounter("Memory", "Cache Bytes", null);
        private PerformanceCounter pageFile = new PerformanceCounter("Paging File", "% Usage", "_Total");
        private PerformanceCounter processorQueueLengh = new PerformanceCounter("System", "Processor Queue Length", null);
        private PerformanceCounter diskQueueLengh = new PerformanceCounter("PhysicalDisk", "Avg. Disk Queue Length", "_Total");
        private PerformanceCounter diskRead = new PerformanceCounter("PhysicalDisk", "Disk Read Bytes/sec", "_Total");
        private PerformanceCounter diskWrite = new PerformanceCounter("PhysicalDisk", "Disk Write Bytes/sec", "_Total");
        private PerformanceCounter diskAverageTimeRead = new PerformanceCounter("PhysicalDisk", "Avg. Disk sec/Read", "_Total");
        private PerformanceCounter diskAverageTimeWrite = new PerformanceCounter("PhysicalDisk", "Avg. Disk sec/Write", "_Total");
        private PerformanceCounter diskTime = new PerformanceCounter("PhysicalDisk", "% Disk Time", "_Total");
        private PerformanceCounter handleCountCounter = new PerformanceCounter("Process", "Handle Count", "_Total");
        private PerformanceCounter threadCount = new PerformanceCounter("Process", "Thread Count", "_Total");
        private PerformanceCounter contentSwitches = new PerformanceCounter("System", "Context Switches/sec", null);
        private PerformanceCounter systemCalls = new PerformanceCounter("System", "System Calls/sec", null);
        private PerformanceCounterCategory performanceNetCounterCategory;
        private PerformanceCounter[] trafficSentCounters;
        private PerformanceCounter[] trafficReceivedCounters;
        private string[] interfaces = null;

        public string NodeName { get; set; }

        public float CPUProcessorTime { get; set; }

        public float CPUPrivilegedTime { get; set; }

        public float CPUInterruptTime { get; set; }

        public float CPUDPCTime { get; set; }

        public float MEMAvailable { get; set; }

        public float MEMCommited { get; set; }

        public float MEMCommitLimit { get; set; }

        public float MEMCommitedPerc { get; set; }

        public float MEMPoolPaged { get; set; }

        public float MEMPoolNonPaged { get; set; }

        public float MEMCached { get; set; }

        public float PageFile { get; set; }

        public float ProcessorQueueLengh { get; set; }

        public float DISCQueueLengh { get; set; }

        public float DISKRead { get; set; }

        public float DISKWrite { get; set; }

        public float DISKAverageTimeRead { get; set; }

        public float DISKAverageTimeWrite { get; set; }

        public float DISKTime { get; set; }

        public float HANDLECountCounter { get; set; }

        public float THREADCount { get; set; }

        public int CONTENTSwitches { get; set; }

        public int SYSTEMCalls { get; set; }

        public float NetTrafficSend { get; set; }

        public float NetTrafficReceive { get; set; }

        public DateTime SamplingTime { get; set; }

        public static SystemInfo GetInstance()
        {
            if (sysinfo == null)
            {
                lock (LockHelper)
                {
                    if (sysinfo == null)
                    {
                        sysinfo = new SystemInfo();
                    }
                }
            }

            return sysinfo;
        }

        public void InitNetCounters()
        {
            this.performanceNetCounterCategory = new PerformanceCounterCategory("Network Interface");
            this.interfaces = this.performanceNetCounterCategory.GetInstanceNames();

            int length = this.interfaces.Length;

            if (length > 0)
            {
                this.trafficSentCounters = new PerformanceCounter[length];
                this.trafficReceivedCounters = new PerformanceCounter[length];
            }

            for (int i = 0; i < length; i++)
            {
                // Initializes a new, read-only instance of the PerformanceCounter class.
                // 1st paramenter: "categoryName"-The name of the performance counter category (performance object) with which 
                //                                this performance counter is associated. 
                // 2nd paramenter: "CounterName" -The name of the performance counter. 
                // 3rd paramenter: "instanceName" -The name of the performance counter category instance, or an empty string (""), if the category contains a single instance. 
                this.trafficReceivedCounters[i] = new PerformanceCounter("Network Interface", "Bytes Sent/sec", this.interfaces[i]);
                this.trafficSentCounters[i] = new PerformanceCounter("Network Interface", "Bytes Sent/sec", this.interfaces[i]);
            }

            // List of all names of the network interfaces
            for (int i = 0; i < length; i++)
            {
                Console.WriteLine("Name netInterface: {0}", this.performanceNetCounterCategory.GetInstanceNames()[i]);
            }
        }

        public void GetProcessorCpuTime()
        {
            float tmp = this.cpuProcessorTime.NextValue();
            this.CPUProcessorTime = (float)Math.Round((double)tmp, 1);
        }

        public void GetCpuPrivilegedTime()
        {
            float tmp = this.cpuPrivilegedTime.NextValue();
            this.CPUPrivilegedTime = (float)Math.Round((double)tmp, 1);
        }

        public void GetCpuinterruptTime()
        {
            float tmp = this.cpuInterruptTime.NextValue();
            this.CPUInterruptTime = (float)Math.Round((double)tmp, 1);
        }

        public void GetcpuDPCTime()
        {
            float tmp = this.cpuDPCTime.NextValue();
            this.CPUDPCTime = (float)Math.Round((double)tmp, 1);
        }

        public void GetPageFile()
        {
            this.PageFile = this.pageFile.NextValue();
        }

        public void GetProcessorQueueLengh()
        {
            this.ProcessorQueueLengh = this.processorQueueLengh.NextValue();
        }

        public void GetMemAvailable()
        {
            this.MEMAvailable = this.memAvailable.NextValue();
        }

        public void GetMemCommited()
        {
            this.MEMCommited = this.memCommited.NextValue() / (1024 * 1024);
        }

        public void GetMemCommitLimit()
        {
            this.MEMCommitLimit = this.memCommitLimit.NextValue() / (1024 * 1024);
        }

        public void GetMemCommitedPerc()
        {
            float tmp = this.memCommitedPerc.NextValue();

            // return the value of Memory Commit Limit
            this.MEMCommitedPerc = (float)Math.Round((double)tmp, 1);
        }

        public void GetMemPoolPaged()
        {
            float tmp = this.memPollPaged.NextValue() / (1024 * 1024);
            this.MEMPoolPaged = (float)Math.Round((double)tmp, 1);
        }

        public void GetMemPoolNonPaged()
        {
            float tmp = this.memPollNonPaged.NextValue() / (1024 * 1024);
            this.MEMPoolNonPaged = (float)Math.Round((double)tmp, 1);
        }

        public void GetMemCachedBytes()
        {
            // return the value of Memory Cached in MBytes
            this.MEMCached = this.memCached.NextValue() / (1024 * 1024);
        }

        public void GetDiskQueueLengh()
        {
            this.DISCQueueLengh = this.diskQueueLengh.NextValue();
        }

        public void GetDiskRead()
        {
            float tmp = this.diskRead.NextValue() / 1024;
            this.DISKRead = (float)Math.Round((double)tmp, 1);
        }

        public void GetDiskWrite()
        {
            float tmp = this.diskWrite.NextValue() / 1024;

            // round 1 digit decimal
            this.DISKWrite = (float)Math.Round((double)tmp, 1);
        }

        public void GetDiskAverageTimeRead()
        {
            float tmp = this.diskAverageTimeRead.NextValue() * 1000;

            // round 1 digit decimal
            this.DISKAverageTimeRead = (float)Math.Round((double)tmp, 1);
        }

        public void GetDiskAverageTimeWrite()
        {
            float tmp = this.diskAverageTimeWrite.NextValue() * 1000;

            // round 1 digit decimal
            this.DISKAverageTimeWrite = (float)Math.Round((double)tmp, 1);
        }

        public void GetDiskTime()
        {
            float tmp = this.diskTime.NextValue();
            this.DISKTime = (float)Math.Round((double)tmp, 1);
        }

        public void GetHandleCountCounter()
        {
            this.HANDLECountCounter = this.handleCountCounter.NextValue();
        }

        public void GetThreadCount()
        {
            this.THREADCount = this.threadCount.NextValue();
        }

        public void GetContentSwitches()
        {
            // convert to integer
            this.CONTENTSwitches = (int)Math.Ceiling(this.contentSwitches.NextValue());
        }

        public void GetsystemCalls()
        {
            // convert to integer
            this.SYSTEMCalls = (int)Math.Ceiling(this.systemCalls.NextValue());
        }

        public void GetCurretTrafficSent()
        {
            int length = this.interfaces.Length;
            float sendSum = 0.0F;

            for (int i = 0; i < length; i++)
            {
                sendSum += this.trafficSentCounters[i].NextValue();
            }

            float tmp = 8 * (sendSum / 1024);
            this.NetTrafficSend = (float)Math.Round((double)tmp, 1);
        }

        public void GetCurretTrafficReceived()
        {
            int length = this.interfaces.Length;
            float receiveSum = 0.0F;

            for (int i = 0; i < length; i++)
            {
                receiveSum += this.trafficReceivedCounters[i].NextValue();
            }

            float tmp = 8 * (receiveSum / 1024);
            this.NetTrafficReceive = (float)Math.Round((double)tmp, 1);
        }

        public void GetSampleTime()
        {
            this.SamplingTime = DateTime.Now;
        }
    }
}