/*
 * MIT License
 *
 * Copyright (c) 2010 - 2021 The OSHI Project Contributors: https://github.com/oshi/oshi/graphs/contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package oshi.demo;

import com.sun.jna.platform.win32.COM.COMException; // NOSONAR squid:S1191

import oshi.driver.windows.wmi.Win32OperatingSystem;
import oshi.util.platform.windows.WmiQueryHandler;

/**
 * Class demonstrating WMI stat performance improvements if the user does COM
 * initialization so OSHI doesn't have to
 */
public class UserComInit {

    private static final int REPETITIONS = 300;

    public static void main(String[] args) {
        wakeUpCom();
        System.out.println("Collecting statistics with default COM setup");
        loopWmiQueries();
        System.out.println("Collecting statistics with user-init COM setup");
        loopWmiQueriesWithUserCom();
    }

    private static void wakeUpCom() {
        // The first COM query can take extra long so just do one separately
        Win32OperatingSystem.queryOsVersion();
    }

    private static void loopWmiQueries() {
        long t = System.nanoTime();
        for (int i = 0; i < REPETITIONS; i++) {
            Win32OperatingSystem.queryOsVersion();
        }
        t = System.nanoTime() - t;
        System.out.println("Average ms per rep: " + t / (1_000_000d * REPETITIONS));
    }

    private static void loopWmiQueriesWithUserCom() {
        // Create instance using existing WmiQueryHandler class for convenience, only to
        // be used for COM init/uninit. This is unnecessary in a user application if
        // they control COM initialization elsewhere.
        WmiQueryHandler handlerForSingleCOMinit = WmiQueryHandler.createInstance();

        // Change query handler class to not initialize COM
        WmiQueryHandler.setInstanceClass(WmiNoComInitQueryHandler.class);
        boolean comInit = false;
        try {
            comInit = handlerForSingleCOMinit.initCOM();

            loopWmiQueries();
        } catch (COMException e) {
            // Ignore for demo. Production code should handle this!
        }
        if (comInit) {
            handlerForSingleCOMinit.unInitCOM();
        }
    }
}

@@ -2569,76 +2569,324 @@
 it. 
-This is unnecessary in a user application if%0A        // they
+Not needed if user initializes COM.%0A        WmiQueryHandler handlerForSingleCOMinit = WmiQueryHandler.createInstance();%0A%0A        boolean singleComInit = false;%0A        try %7B%0A            // Initialize using the default query handler. This is unnecessary in a user%0A            // application if the application
  control
  COM
@@ -2881,16 +2881,17 @@
  control
+s
  COM ini
@@ -2917,39 +2917,43 @@
 re.%0A        
-WmiQueryHandler
+    singleComInit =
  handlerForS
@@ -2968,46 +2968,25 @@
 init
- = WmiQueryHandler.createInstance
+.initCOM
 ();%0A%0A
+    
     
@@ -3041,32 +3041,36 @@
 ize COM%0A        
+   
+ 
 WmiQueryHandler.
@@ -3122,112 +3122,8 @@
 ss);
-%0A        boolean comInit = false;%0A        try %7B%0A            comInit = handlerForSingleCOMinit.initCOM();
 %0A%0A  
@@ -3266,22 +3266,111 @@
    %7D
-%0A        if (c
+ finally %7B%0A            // User should ununitialize COM in their own application%0A            if (singleC
 omIn
@@ -3371,24 +3371,28 @@
 eComInit) %7B%0A
+    
             
@@ -3424,24 +3424,38 @@
 nInitCOM();%0A
+            %7D%0A
         %7D%0A  

Reorder COM init demo for clarity