/**
 * MIT License
 *
 * Copyright (c) 2010 - 2020 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.hardware.platform.windows;

import static oshi.util.Memoizer.memoize;

import java.util.function.Supplier;

import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiQuery; // NOSONAR squid:S1191
import com.sun.jna.platform.win32.COM.WbemcliUtil.WmiResult;

import oshi.hardware.common.AbstractFirmware;
import oshi.util.Constants;
import oshi.util.Util;
import oshi.util.platform.windows.WmiQueryHandler;
import oshi.util.platform.windows.WmiUtil;

/**
 * Firmware data obtained from WMI
 */
final class WindowsFirmware extends AbstractFirmware {

    private final Supplier<WmiStrings> wmi = memoize(this::queryWmi);

    @Override
    public String getManufacturer() {
        return wmi.get().manufacturer;
    }

    @Override
    public String getName() {
        return wmi.get().name;
    }

    @Override
    public String getDescription() {
        return wmi.get().description;
    }

    @Override
    public String getVersion() {
        return wmi.get().version;
    }

    @Override
    public String getReleaseDate() {
        return wmi.get().releaseDate;
    }

    private WmiStrings queryWmi() {
        WmiQuery<BiosProperty> biosQuery = new WmiQuery<>("Win32_BIOS where PrimaryBIOS=true", BiosProperty.class);
        WmiResult<BiosProperty> win32BIOS = WmiQueryHandler.createInstance().queryWMI(biosQuery);
        if (win32BIOS.getResultCount() > 0) {
            return new WmiStrings(WmiUtil.getString(win32BIOS, BiosProperty.MANUFACTURER, 0),
                    WmiUtil.getString(win32BIOS, BiosProperty.NAME, 0),
                    WmiUtil.getString(win32BIOS, BiosProperty.DESCRIPTION, 0),
                    WmiUtil.getString(win32BIOS, BiosProperty.VERSION, 0),
                    WmiUtil.getDateString(win32BIOS, BiosProperty.RELEASEDATE, 0));
        }
        return new WmiStrings(Constants.UNKNOWN, Constants.UNKNOWN, Constants.UNKNOWN, Constants.UNKNOWN,
                Constants.UNKNOWN);
    }

    enum BiosProperty {
        MANUFACTURER, NAME, DESCRIPTION, VERSION, RELEASEDATE;
    }

    private static final class WmiStrings {
        private final String releaseDate;
        private final String manufacturer;
        private final String version;
        private final String name;
        private final String description;

        private WmiStrings(String releaseDate, String manufacturer, String version, String name, String description) {
            this.releaseDate = Util.isBlank(releaseDate) ? Constants.UNKNOWN : releaseDate;
            this.manufacturer = Util.isBlank(manufacturer) ? Constants.UNKNOWN : manufacturer;
            this.version = Util.isBlank(version) ? Constants.UNKNOWN : version;
            this.name = Util.isBlank(name) ? Constants.UNKNOWN : name;
            this.description = Util.isBlank(description) ? Constants.UNKNOWN : description;
        }
    }
}

@@ -3317,27 +3317,28 @@
  String 
-releaseDate
+manufacturer
 ;%0A      
@@ -3356,36 +3356,28 @@
 inal String 
-manufacturer
+name
 ;%0A        pr
@@ -3395,20 +3395,24 @@
  String 
-vers
+descript
 ion;%0A   
@@ -3429,36 +3429,39 @@
 te final String 
-name
+version
 ;%0A        privat
@@ -3475,27 +3475,27 @@
  String 
-description
+releaseDate
 ;%0A%0A     
@@ -3527,40 +3527,33 @@
 ing 
-releaseDate, String manufacturer
+manufacturer, String name
 , St
@@ -3557,20 +3557,24 @@
  String 
-vers
+descript
 ion, Str
@@ -3569,36 +3569,39 @@
 ription, String 
-name
+version
 , String descrip
@@ -3593,27 +3593,27 @@
  String 
-description
+releaseDate
 ) %7B%0A    
@@ -3625,27 +3625,28 @@
    this.
-releaseDate
+manufacturer
  = Util.
@@ -3653,27 +3653,28 @@
 isBlank(
-releaseDate
+manufacturer
 ) ? Cons
@@ -3689,27 +3689,28 @@
 KNOWN : 
-releaseDate
+manufacturer
 ;%0A      
@@ -3716,36 +3716,28 @@
        this.
-manufacturer
+name
  = Util.isBl
@@ -3736,36 +3736,28 @@
 til.isBlank(
-manufacturer
+name
 ) ? Constant
@@ -3764,36 +3764,28 @@
 s.UNKNOWN : 
-manufacturer
+name
 ;%0A          
@@ -3791,20 +3791,24 @@
    this.
-vers
+descript
 ion = Ut
@@ -3818,20 +3818,24 @@
 isBlank(
-vers
+descript
 ion) ? C
@@ -3853,20 +3853,24 @@
 KNOWN : 
-vers
+descript
 ion;%0A   
@@ -3875,36 +3875,39 @@
            this.
-name
+version
  = Util.isBlank(
@@ -3898,36 +3898,39 @@
  = Util.isBlank(
-name
+version
 ) ? Constants.UN
@@ -3929,36 +3929,39 @@
 tants.UNKNOWN : 
-name
+version
 ;%0A            th
@@ -3959,35 +3959,35 @@
        this.
-description
+releaseDate
  = Util.isBl
@@ -3986,35 +3986,35 @@
 til.isBlank(
-description
+releaseDate
 ) ? Constant
@@ -4021,35 +4021,35 @@
 s.UNKNOWN : 
-description
+releaseDate
 ;%0A        %7D%0A

Fix Windows firmware field ordering (#1093)