package main

import (
	"fmt"
	"os/exec"
	"strconv"
	"strings"

	"golang.org/x/text/encoding/simplifiedchinese"
)

func execcmd_base(cmdargs string) (string, []string, error) {
	if cmdargs == "" {
		return "", nil, fmt.Errorf("NULL COMMAND")
	}

	var app string
	var appargs []string

	spaceindex := strings.Index(cmdargs, " ")
	if spaceindex != -1 {
		app = cmdargs[:spaceindex]
		appargs = strings.Split(cmdargs[spaceindex+1:], " ")
	} else {
		app = cmdargs
		appargs[0] = ""
	}

	return app, appargs, nil
}
func Execcmd_nowait(cmdargs string) {
	app, appargs, err := execcmd_base(cmdargs)
	if err != nil {
		fmt.Print(err)
		return
	}
	if err := exec.Command(app, appargs...).Start(); err != nil {
		fmt.Print(err)
		return
	}
}
func Execcmd_wait(cmdargs string) {
	app, appargs, err := execcmd_base(cmdargs)
	if err != nil {
		return
	}
	cmd := exec.Command(app, appargs...)
	if err := cmd.Start(); err != nil {
	}
	err = cmd.Wait()
	if err != nil {
	}
}
func PSCommandOutput(cmd string) (string, error) {
	if cmd == "" {
		return "", fmt.Errorf("Lost Paramter")
	}
	cmd = "powershell -command -WindowStyle Hidden " + cmd
	app, appargs, err := execcmd_base(cmd)
	if err != nil {
		return "", err
	}
	r, err := exec.Command(app, appargs...).Output()
	if err != nil {
		return "", err
	}
	out, err := simplifiedchinese.GBK.NewDecoder().Bytes(r)
	if err != nil {
		return "", err
	}
	return string(out), nil

}
func PSCommandOutputNoSplit(cmd string) (string, error) {
	if cmd == "" {
		return "", fmt.Errorf("Lost Paramter")
	}
	r, err := exec.Command("powershell", "-command", cmd).Output()
	if err != nil {
		return "", err
	}
	return string(r), nil

}
func getHardwareCPUForPS() (string, string, string, string) {

	cpuNameUN, _ := PSCommandOutputNoSplit("Get-WmiObject -Class Win32_Processor | Select  Name")
	cpuName := strings.TrimSpace(strings.Split(cpuNameUN, "\n")[3])

	cpuCountUN, _ := PSCommandOutputNoSplit("Get-WmiObject -Class Win32_Processor | select Name |measure  | select count")
	cpuCount := strings.TrimSpace(strings.Split(cpuCountUN, "\n")[3])

	cpuCoresUN, _ := PSCommandOutputNoSplit("Get-WmiObject -Class Win32_Processor | select NumberOfCores")
	cpuCores := strings.TrimSpace(strings.Split(cpuCoresUN, "\n")[3])

	cpuLogicalProcessorsUN, _ := PSCommandOutputNoSplit("Get-WmiObject -Class Win32_Processor | select NumberOfLogicalProcessors")
	cpuLogicalProcessors := strings.TrimSpace(strings.Split(cpuLogicalProcessorsUN, "\n")[3])

	return cpuCount, cpuName, cpuCores, cpuLogicalProcessors
}
func getHardwareMemoryForPS() ([]int, []string, []string, int) {

	Capacity := make([]int, 2)
	Speed := make([]string, 2)
	MemoryType := make([]string, 2)
	var c, j int

	menUN, _ := PSCommandOutputNoSplit("Get-WmiObject -Class Win32_PhysicalMemory -Property Capacity,Speed,MemoryType")

	for _, line := range strings.Split(menUN, "\n") {
		if strings.Index(line, "Capacity") != -1 {
			mi := strings.TrimSpace(strings.Split(line, ":")[1])
			m, _ := strconv.ParseInt(mi, 10, 64)

			if j >= 2 {
				Capacity = append(Capacity, int(m/1024/1024/1024))
			} else {
				Capacity[j] = int(m / 1024 / 1024 / 1024)
			}

			c++
		} else if strings.Index(line, "Speed") != -1 {
			m := strings.TrimSpace(strings.Split(line, ":")[1])
			if j >= 2 {
				Speed = append(Speed, m)
			} else {
				Speed[j] = m
			}
			c++
		} else if strings.Index(line, "MemoryType") != -1 {
			m := strings.TrimSpace(strings.Split(line, ":")[1])
			switch m {
			case "21":
				m = "DDR2"
			case "22":
				m = "DDR2 FB-DIMM"
			case "24":
				m = "DDR3"
			case "26":
				m = "DDR4"
			default:
				m = ""
			}
			if j >= 2 {
				MemoryType = append(MemoryType, m)
			} else {
				MemoryType[j] = m
			}
		}
		if c == 2 {
			j++
			c = 0
		}

	}
	return Capacity, Speed, MemoryType, j - 1
}

func getHardwareHardDiskForPS(mini bool) ([]string, []int64, []string, int) {
	MediaType := make([]string, 2)
	FriendlyName := make([]string, 2)
	Sizen := make([]int64, 2)
	var c, j int
	diskUN, _ := PSCommandOutputNoSplit("Get-PhysicalDisk |select mediaType,FriendlyName,Size | format-list")
	for _, line := range strings.Split(diskUN, "\n") {
		if strings.Index(line, "MediaType") != -1 {
			m := strings.TrimSpace(strings.Split(line, ":")[1])

			// 如果是小白
			if mini {
				switch m {
				case "SSD":
					m = "固态硬盘"
				case "HDD":
					m = "机械硬盘"
				}
			}

			if j >= 2 {
				MediaType = append(MediaType, m)
			} else {
				MediaType[j] = m
			}
			c++

		} else if strings.Index(line, "FriendlyName") != -1 {
			m := strings.TrimSpace(strings.Split(line, ":")[1])

			if j >= 2 {
				FriendlyName = append(FriendlyName, m)
			} else {
				FriendlyName[j] = m
			}

			c++
		} else if strings.Index(line, "Size") != -1 {
			Size := strings.TrimSpace(strings.Split(line, ":")[1])
			Sizei, _ := strconv.ParseInt(Size, 10, 64)
			m := Sizei / 1024 / 1024 / 1024

			if j >= 2 {
				Sizen = append(Sizen, m)
			} else {
				Sizen[j] = m
			}
			c++

		}
		if c == 3 {
			j++
			c = 0
		}

	}
	// for i := 0; i <= j; i++ {
	// 	fmt.Printf("%s %dGB %s\n", FriendlyName[i], Sizen[i], MediaType[i])
	// }
	return FriendlyName, Sizen, MediaType, j - 1
}

func main() {
	var ch = make(chan int)
	var Memory, Disk string

	fmt.Println("查看硬件(CPU、内存、硬盘)小工具     -- made in 陶腾飞(2022年3月26日)")
	// cpu
	go func() {
		<-ch

		cpuCount, cpuName, cpuCores, cpuLogicalProcessors := getHardwareCPUForPS()
		cpu := fmt.Sprintf("%s * %s %s核 %s线程", cpuCount, cpuName, cpuCores, cpuLogicalProcessors)
		fmt.Printf("CPU:%s\n", cpu)

	}()
	ch <- 1

	// 内存
	go func() {

		<-ch
		Capacity, Speed, MemoryType, mCount := getHardwareMemoryForPS()
		for i := 0; i <= mCount; i++ {
			Memory += fmt.Sprintf("%dGB %sMhz %s,", Capacity[i], Speed[i], MemoryType[i])
		}
		fmt.Printf("Memory:%s\n", Memory[0:len(Memory)-1])

	}()
	ch <- 1

	// 硬盘
	go func() {
		<-ch

		_, Sizen, MediaType, hCount := getHardwareHardDiskForPS(false)
		for i := 0; i <= hCount; i++ {
			Disk += fmt.Sprintf("%dGB %s,", Sizen[i], MediaType[i])
		}

		Disk = Disk[0 : len(Disk)-1]
		fmt.Printf("Disk:%s\n", Disk)

	}()
	ch <- 1
	fmt.Scanln()
	fmt.Scanln()
}
