// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package winutils

import (
	"crypto/md5"
	"fmt"
	"io"
	"io/ioutil"
	"path"
	"regexp"
	"strconv"
	"strings"
	"time"

	"yunion.io/x/log"
	"yunion.io/x/pkg/utils"

	"yunion.io/x/onecloud/pkg/util/procutils"
	"yunion.io/x/onecloud/pkg/util/regutils2"
)

var _CHNTPW_PATH string

func SetChntpwPath(spath string) {
	_CHNTPW_PATH = spath
}

func GetChntpwPath() string {
	if len(_CHNTPW_PATH) == 0 {
		_CHNTPW_PATH = "/usr/local/bin/chntpw.static"
	}
	return _CHNTPW_PATH
}

const (
	SYSTEM   = "system"
	SOFTWARE = "software"
	SECURITY = "security"
	SAM      = "sam"
	CONFIRM  = "y"
)

func NewWinRegTool(spath string) *SWinRegTool {
	return &SWinRegTool{ConfigPath: spath}
}

func CheckTool(spath string) bool {
	return procutils.NewCommand(spath, "-h").Run() == nil
}

type SWinRegTool struct {
	ConfigPath   string
	SystemPath   string
	SoftwarePath string
	SamPath      string
	SecurityPath string
}

func (w *SWinRegTool) CheckPath() bool {
	files, err := ioutil.ReadDir(w.ConfigPath)
	if err != nil {
		log.Errorln(err)
		return false
	}

	for _, file := range files {
		switch strings.ToLower(file.Name()) {
		case SYSTEM:
			w.SystemPath = path.Join(w.ConfigPath, file.Name())
		case SOFTWARE:
			w.SoftwarePath = path.Join(w.ConfigPath, file.Name())
		case SAM:
			w.SamPath = path.Join(w.ConfigPath, file.Name())
		case SECURITY:
			w.SecurityPath = path.Join(w.ConfigPath, file.Name())
		}
	}
	if len(w.SystemPath) > 0 && len(w.SoftwarePath) > 0 &&
		len(w.SamPath) > 0 && len(w.SecurityPath) > 0 {
		return true
	}
	return false
}

func (w *SWinRegTool) GetUsers() map[string]bool {
	output, err := procutils.NewCommand(GetChntpwPath(), "-l", w.SamPath).Output()
	if err != nil {
		log.Errorln(err)
		return nil
	}

	users := map[string]bool{}
	re := regexp.MustCompile(
		`\|\s*\w+\s*\|\s*(?P<user>\w+)\s*\|\s*(ADMIN)?\s*\|\s*(?P<lock>(dis/lock|\*BLANK\*)?)`)
	for _, line := range strings.Split(string(output), "\n") {
		m := regutils2.GetParams(re, line)
		if len(m) > 0 {
			user, _ := m["user"]
			if strings.ToLower(user) != "guest" {
				lock, _ := m["lock"]
				users[user] = lock != "dis/lock"
			}
		}
	}
	return users
}

func (w *SWinRegTool) samChange(user string, seq ...string) error {
	proc := procutils.NewCommand(GetChntpwPath(), "-u", user, w.SamPath, w.SystemPath, w.SecurityPath)
	stdin, err := proc.StdinPipe()
	if err != nil {
		return err
	}
	defer stdin.Close()

	outb, err := proc.StdoutPipe()
	if err != nil {
		return err
	}
	defer outb.Close()

	errb, err := proc.StderrPipe()
	if err != nil {
		return err
	}
	defer errb.Close()

	if err := proc.Start(); err != nil {
		return err
	}

	io.WriteString(stdin, "n\n")
	for _, s := range seq {
		io.WriteString(stdin, s+"\n")
	}
	io.WriteString(stdin, CONFIRM+"\n")
	stdoutPut, err := ioutil.ReadAll(outb)
	if err != nil {
		return err
	}
	stderrOutPut, err := ioutil.ReadAll(errb)
	if err != nil {
		return err
	}
	log.Debugf("Sam change %s %s", stdoutPut, stderrOutPut)

	done := make(chan error, 1)
	go func() {
		done <- proc.Wait()
	}()
	select {
	case <-time.After(time.Millisecond * 100):
		proc.Kill()
		return fmt.Errorf("Failed to change SAM password, not exit cleanly")
	case err := <-done:
		if err != nil {
			if exitStatus, ok := proc.GetExitStatus(err); ok {
				if exitStatus == 2 {
					return nil
				}
			}
			log.Errorf("Failed to change SAM password")
			return err
		} else {
			return nil
		}
	}
}

func (w *SWinRegTool) ChangePassword(user, password string) error {
	return w.samChange(user, "2", password)
}

func (w *SWinRegTool) RemovePassword(user string) error {
	return w.samChange(user, "2")
}

func (w *SWinRegTool) UnlockUser(user string) error {
	return w.samChange(user, "4")
}

func (w *SWinRegTool) GetRegFile(regPath string) (string, []string) {
	re := regexp.MustCompile(`\\`)
	vals := re.Split(regPath, -1)
	regSeg := []string{}
	for _, val := range vals {
		if len(val) > 0 {
			regSeg = append(regSeg, val)
		}
	}

	if regSeg[0] == "HKLM" {
		regSeg = regSeg[1:]
	}
	if strings.ToLower(regSeg[0]) == SOFTWARE {
		regSeg = regSeg[1:]
		return w.SoftwarePath, regSeg
	} else if strings.ToLower(regSeg[0]) == SYSTEM {
		regSeg = regSeg[1:]
		return w.SystemPath, regSeg
	} else {
		return "", nil
	}
}

func (w *SWinRegTool) showRegistry(spath string, keySeg []string, verb string) ([]string, error) {
	proc := procutils.NewCommand(GetChntpwPath(), spath)
	stdin, err := proc.StdinPipe()
	if err != nil {
		return nil, err
	}
	defer stdin.Close()

	outb, err := proc.StdoutPipe()
	if err != nil {
		return nil, err
	}
	defer outb.Close()

	// errb, err := proc.StderrPipe()
	// if err != nil {
	// 	return nil, err
	// }
	// defer errb.Close()

	if err := proc.Start(); err != nil {
		return nil, err
	}
	keypath := strings.Join(keySeg, "\\")
	io.WriteString(stdin, fmt.Sprintf("%s %s\n", verb, keypath))
	io.WriteString(stdin, "q\n")
	stdoutPut, err := ioutil.ReadAll(outb)
	if err != nil {
		return nil, err
	}
	time.Sleep(time.Millisecond * 100)

	done := make(chan error, 1)
	go func() {
		done <- proc.Wait()
	}()
	select {
	case <-time.After(time.Millisecond * 100):
		proc.Kill()
	case err := <-done:
		if err != nil {
			return nil, err
		}
	}
	return strings.Split(string(stdoutPut), "\n"), nil
}

func (w *SWinRegTool) getRegistry(spath string, keySeg []string) string {
	keyPath := strings.Join(keySeg, "\\")
	lines, err := w.showRegistry(spath, keySeg, "cat")
	if err != nil {
		log.Errorln(err)
		return ""
	}
	for i, line := range lines {
		if len(keyPath) > 85 {
			keyPath = keyPath[:85]
		}
		if strings.Contains(line, fmt.Sprintf("> Value <%s> of type REG_", keyPath)) {
			return lines[i+1]
		}
	}
	return ""
}

type sRegistry struct {
	Key  string
	Type string
	Size string
}

func (w *SWinRegTool) listRegistry(spath string, keySeg []string) ([]string, []sRegistry, error) {
	lines, err := w.showRegistry(spath, keySeg, "ls")
	if err != nil {
		return nil, nil, err
	}
	keys := []string{}
	values := []sRegistry{}
	keyPattern := regexp.MustCompile("^<(?P<key>[^>]+)>$")
	valPattern := regexp.MustCompile(`^(?P<size>\d+)\s+(?P<type>REG\_\w+)\s+<(?P<key>[^>]+)>\s*`)
	for _, line := range lines {
		line = strings.TrimSpace(line)
		m := regutils2.GetParams(keyPattern, line)
		if len(m) > 0 {
			keys = append(keys, m["key"])
		}
		m = regutils2.GetParams(valPattern, line)
		if len(m) > 0 {
			values = append(values, sRegistry{m["key"], m["type"], m["size"]})
		}
	}

	return keys, values, nil
}

func (w *SWinRegTool) cmdRegistry(spath string, ops []string, retcode []int) bool {
	log.Infof("cmdRegistry %s -e %v", GetChntpwPath(), spath)
	proc := procutils.NewCommand(GetChntpwPath(), "-e", spath)
	stdin, err := proc.StdinPipe()
	if err != nil {
		log.Errorln(err)
		return false
	}
	defer stdin.Close()

	outb, err := proc.StdoutPipe()
	if err != nil {
		log.Errorln(err)
		return false
	}
	defer outb.Close()

	errb, err := proc.StderrPipe()
	if err != nil {
		log.Errorln(err)
		return false
	}
	defer errb.Close()

	if err := proc.Start(); err != nil {
		log.Errorln(err)
		return false
	}

	for _, op := range ops {
		log.Debugf("Input: %s", op)
		io.WriteString(stdin, op+"\n")
	}
	io.WriteString(stdin, "q\n")
	io.WriteString(stdin, CONFIRM+"\n")
	stdoutPut, err := ioutil.ReadAll(outb)
	if err != nil {
		log.Errorln(err)
		return false
	}
	stderrOutPut, err := ioutil.ReadAll(errb)
	if err != nil {
		log.Errorln(err)
		return false
	}
	log.Debugf("Cmd registry %s %s", stdoutPut, stderrOutPut)

	done := make(chan error, 1)
	go func() {
		done <- proc.Wait()
	}()
	select {
	case <-time.After(time.Millisecond * 1000):
		log.Errorf("Cmd registry timeout")
		if err := proc.Kill(); err != nil {
			log.Errorf("kill cmd registry process failed %s", err)
		}
	case err := <-done:
		if err != nil {
			if exitStatus, ok := proc.GetExitStatus(err); ok {
				log.Errorf("ops %v exit status: %d", ops, exitStatus)
				if in, _ := utils.InArray(exitStatus, retcode); in {
					return true
				}
			}
		} else {
			if in, _ := utils.InArray(0, retcode); in {
				return true
			}
		}
	}
	return false
}

func (w *SWinRegTool) setRegistry(spath string, keySeg []string, value string) bool {
	cmds := make([]string, 0)
	for i := range keySeg {
		if i < len(keySeg)-1 {
			cmds = append(cmds, fmt.Sprintf("cd %s", keySeg[i]))
		} else {
			cmds = append(cmds, fmt.Sprintf("ed %s", keySeg[i]))
		}
	}
	cmds = append(cmds, value)
	return w.cmdRegistry(spath, cmds, []int{0})
}

func (w *SWinRegTool) delRegistry(spath string, keySeg []string) bool {
	cmds := make([]string, 0)
	for i := range keySeg {
		if i < len(keySeg)-1 {
			cmds = append(cmds, fmt.Sprintf("cd %s", keySeg[i]))
		} else {
			cmds = append(cmds, fmt.Sprintf("rdel %s", keySeg[i]))
		}
	}
	return w.cmdRegistry(spath, cmds, []int{0})
}

func (w *SWinRegTool) mkdir(spath string, keySeg []string) bool {
	return w.cmdRegistry(spath,
		[]string{
			fmt.Sprintf("cd %s", strings.Join(keySeg[:len(keySeg)-1], "\\")),
			fmt.Sprintf("nk %s", keySeg[len(keySeg)-1]),
		}, []int{0, 2})
}

func (w *SWinRegTool) keyExists(spath string, keySeg []string) bool {
	keys, _, err := w.listRegistry(spath, keySeg[:len(keySeg)-1])
	if err != nil {
		log.Errorln(err)
		return false
	}
	if utils.IsInStringArray(keySeg[len(keySeg)-1], keys) {
		return true
	}
	return false
}

func (w *SWinRegTool) valExists(spath string, keySeg []string) bool {
	_, vals, err := w.listRegistry(spath, keySeg[:len(keySeg)-1])
	if err != nil {
		log.Errorln(err)
		return false
	}
	for _, val := range vals {
		if val.Key == keySeg[len(keySeg)-1] {
			return true
		}
	}
	return false
}

func (w *SWinRegTool) mkdir_P(spath string, keySeg []string) bool {
	seg := []string{}
	for _, k := range keySeg {
		seg = append(seg, k)
		if !w.keyExists(spath, seg) {
			if !w.mkdir(spath, seg) {
				return false
			}
		}
	}
	return true
}

func (w *SWinRegTool) newValue(spath string, keySeg []string, regtype, val string) bool {
	REG_TYPE_TBL := []string{
		"REG_NONE",
		"REG_SZ",
		"REG_EXPAND_SZ",
		"REG_BINARY",
		"REG_DWORD",
		"REG_DWORD_BIG_ENDIAN",
		"REG_LINK",
		"REG_MULTI_SZ",
		"REG_RESOUCE_LIST",
		"REG_FULL_RES_DESC",
		"REG_RES_REQ",
		"REG_QWORD",
	}

	ok, idx := utils.InStringArray(regtype, REG_TYPE_TBL)
	if !ok {
		return false
	}

	cmds := []string{
		fmt.Sprintf("cd %s", strings.Join(keySeg[:len(keySeg)-1], "\\")),
		fmt.Sprintf("nv %x %s", idx, keySeg[len(keySeg)-1]),
		fmt.Sprintf("ed %s", keySeg[len(keySeg)-1]),
	}

	if regtype == "REG_QWORD" {
		cmds = append(cmds, "16", ": 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0", "s")
	} else {
		cmds = append(cmds, val)
	}
	return w.cmdRegistry(spath, cmds, []int{0})
}

func (w *SWinRegTool) GetRegistry(keyPath string) string {
	p1, p2s := w.GetRegFile(keyPath)
	if len(p1) == 0 && len(p2s) == 0 {
		return ""
	} else {
		return w.getRegistry(p1, p2s)
	}
}

func (w *SWinRegTool) ListRegistry(keyPath string) ([]string, []sRegistry) {
	p1, p2s := w.GetRegFile(keyPath)
	if len(p1) == 0 && len(p2s) == 0 {
		return nil, nil
	} else {
		v1, v2, err := w.listRegistry(p1, p2s)
		if err != nil {
			log.Errorln(err)
			return nil, nil
		}
		return v1, v2
	}
}

func (w *SWinRegTool) SetRegistry(keyPath, value, regtype string) bool {
	p1, p2s := w.GetRegFile(keyPath)
	if len(p1) == 0 && len(p2s) == 0 {
		return false
	} else {
		if w.valExists(p1, p2s) {
			return w.setRegistry(p1, p2s, value)
		} else {
			if !w.keyExists(p1, p2s[:len(p2s)-1]) {
				if !w.mkdir_P(p1, p2s[:len(p2s)-1]) {
					return false
				}
			}
			return w.newValue(p1, p2s, regtype, value)
		}
	}
}

func (w *SWinRegTool) DelRegistry(keyPath string) bool {
	p1, p2s := w.GetRegFile(keyPath)
	if len(p1) == 0 && len(p2s) == 0 {
		return false
	} else {
		if w.keyExists(p1, p2s) {
			ret := w.delRegistry(p1, p2s)
			log.Debugf("delete %s %s %v", p1, p2s, ret)
			return ret
		}
		return false
	}
}

func (w *SWinRegTool) KeyExists(keyPath string) bool {
	p1, p2s := w.GetRegFile(keyPath)
	if len(p1) == 0 && len(p2s) == 0 {
		return false
	} else {
		return w.keyExists(p1, p2s)
	}
}

func (w *SWinRegTool) MkdirP(keyPath string) bool {
	p1, p2s := w.GetRegFile(keyPath)
	if len(p1) == 0 && len(p2s) == 0 {
		return false
	} else {
		return w.mkdir_P(p1, p2s)
	}
}

func (w *SWinRegTool) GetCcsKey() string {
	ver := w.GetRegistry(`HKLM\SYSTEM\Select\Current`)
	log.Debugf("Current Control set %s", ver)
	return fmt.Sprintf("ControlSet%s", ver[len(ver)-3:])
}

func (w *SWinRegTool) GetCcsKeyPath() string {
	return fmt.Sprintf(`HKLM\SYSTEM\%s`, w.GetCcsKey())
}

func (w *SWinRegTool) getComputerNameKeyPath() string {
	key := w.GetCcsKey()
	return key + `\Control\ComputerName\ComputerName\ComputerName`
}

func (w *SWinRegTool) GetComputerName() string {
	key := w.getComputerNameKeyPath()
	return w.GetRegistry(key)
}

func (w *SWinRegTool) setComputerName(cn string) {
	MAX_COMPUTER_NAME_LEN := 15
	COMMON_PREFIX_LEN := 10
	if len(cn) > MAX_COMPUTER_NAME_LEN {
		suffix := cn[COMMON_PREFIX_LEN:]
		suffixlen := MAX_COMPUTER_NAME_LEN - COMMON_PREFIX_LEN
		md5sum := md5.Sum([]byte(suffix))
		cn = cn[:COMMON_PREFIX_LEN] + string(md5sum[:])[:suffixlen]
	}
	key := w.getComputerNameKeyPath()
	w.SetRegistry(key, cn, "")
}

func (w *SWinRegTool) SetHostname(hostname, domain string) {
	tcpipKey := w.GetCcsKeyPath() + `\Services\Tcpip\Parameters`
	hnKey := tcpipKey + `\Hostname`
	dmKey := tcpipKey + `\Domain`
	nvHnKey := tcpipKey + `\NV Hostname`
	nvDmKey := tcpipKey + `\NV Domain`
	w.SetRegistry(hnKey, hostname, "REG_SZ")
	w.SetRegistry(dmKey, domain, "REG_SZ")
	w.SetRegistry(nvHnKey, hostname, "REG_SZ")
	w.SetRegistry(nvDmKey, domain, "REG_SZ")
}

func (w *SWinRegTool) SetDnsServer(nameserver, searchlist string) {
	tcpipKey := w.GetCcsKeyPath() + `\Services\Tcpip\Parameters`
	ns_key := tcpipKey + `\NameServer`
	search_key := tcpipKey + `\SearchList`
	w.SetRegistry(ns_key, nameserver, "REG_SZ")
	w.SetRegistry(search_key, searchlist, "REG_SZ")
}

func (w *SWinRegTool) GetProductName() string {
	prodKey := `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProductName`
	prodName := w.GetRegistry(prodKey)

	if strings.Contains(prodName, "Windows 10") {
		// check build number to determine whether it's actually Windows 11
		buildNumStr := w.GetCurrentBuildNumber()
		if buildNum, err := strconv.Atoi(strings.TrimSpace(buildNumStr)); err == nil && buildNum >= 22000 {
			prodName = strings.Replace(prodName, "Windows 10", "Windows 11", 1)
		}
	}
	return prodName
}

func (w *SWinRegTool) GetCurrentBuildNumber() string {
	prodKey := `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentBuildNumber`
	return w.GetRegistry(prodKey)
}

func (w *SWinRegTool) GetVersion() string {
	prodKey := `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\CurrentVersion`
	return w.GetRegistry(prodKey)
}

func (w *SWinRegTool) GetInstallLanguage() string {
	nlsTbl := map[string]string{"0804": "zh_CN", "0404": "zh_TW", "0c04": "zh_HK",
		"1004": "zh_SG", "0409": "en_US", "0809": "en_UK"}
	key := w.GetCcsKeyPath()
	key += `\Control\Nls\Language\InstallLanguage`
	val := w.GetRegistry(key)
	if xval, ok := nlsTbl[key]; ok {
		return xval
	} else {
		return val
	}
}

func (w *SWinRegTool) LogontypePath() string {
	return `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\LogonType`
}

func (w *SWinRegTool) GetLogontype() string {
	return w.GetRegistry(w.LogontypePath())
}

func (w *SWinRegTool) SetLogontype(val string) {
	w.SetRegistry(w.LogontypePath(), val, "")
}

func (w *SWinRegTool) DefaultAccountPath() string {
	return `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\DefaultUserName`
}

func (w *SWinRegTool) GetDefaultAccount() string {
	return w.GetRegistry(w.DefaultAccountPath())
}

func (w *SWinRegTool) SetDefaultAccount(user string) {
	w.SetRegistry(w.DefaultAccountPath(), user, "")
}

func (w *SWinRegTool) GpeditScriptPath() string {
	return `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\Scripts`
}

func (w *SWinRegTool) GpeditScriptStatePath() string {
	return `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\Scripts`
}

func (w *SWinRegTool) GetGpeditStartScripts() []string {
	scriptKey := w.GpeditScriptPath() + `\Startup\0`
	keys, _ := w.ListRegistry(scriptKey)
	ret := []string{}
	for _, k := range keys {
		spath := scriptKey + (fmt.Sprintf(`\%s\Script`, k))
		val := w.GetRegistry(spath)
		ret = append(ret, val)
	}
	return ret
}

func (w *SWinRegTool) IsGpeditStartScriptInstalled(script string) bool {
	scripts := w.GetGpeditStartScripts()
	return utils.IsInStringArray(script, scripts)
}

func (w *SWinRegTool) InstallGpeditStartScript(script string) {
	if w.IsGpeditStartScriptInstalled(script) {
		return
	}
	w.installGpeditStartScript(script, w.GpeditScriptPath())
	w.installGpeditStartScript(script, w.GpeditScriptStatePath())
}

func (w *SWinRegTool) GetGpoDisplayname() string {
	spath := `HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Group Policy\State\Machine\GPO-List\0\DisplayName`
	return w.GetRegistry(spath)
}

func (w *SWinRegTool) installGpeditStartScript(script, scriptPath string) {
	idx := 0
	if !w.KeyExists(scriptPath + `\Startup`) {
		w.MkdirP(scriptPath + `\Startup`)
		w.MkdirP(scriptPath + `\Shutdown`)
		dsname := "Local Group Policy"
		kvts := [][3]string{
			{"GPO-ID", "LocalGPO", "REG_SZ"},
			{"SOM-ID", "Local", "REG_SZ"},
			{"FileSysPath", `C:\Windows\System32\GroupPolicy\Machine`, "REG_SZ"},
			{"DisplayName", dsname, "REG_SZ"},
			{"GPOName", dsname, "REG_SZ"},
			{"PSScriptOrder", "1", "REG_DWORD"},
		}
		for _, kvt := range kvts {
			w.SetRegistry(fmt.Sprintf(`%s\Startup\0\%s`, scriptPath, kvt[0]), kvt[1], kvt[2])
		}
	} else {
		for w.KeyExists(scriptPath + (fmt.Sprintf(`\Startup\0\%d`, idx))) {
			idx += 1
		}
	}

	// `%WINDIR%\cloudboot.bat`
	kvts := [][3]string{
		{"Script", script, "REG_SZ"},
		{"Parameters", `%WINDIR%\cloudboot.bat`, "REG_SZ"},
		{"ExecTime", "", "REG_QWORD"},
		{"IsPowershell", "0", "REG_DWORD"},
	}
	for _, kvt := range kvts {
		w.SetRegistry(fmt.Sprintf(`%s\Startup\0\%d\%s`, scriptPath, idx, kvt[0]), kvt[1], kvt[2])
	}
}

func (w *SWinRegTool) EnableRdp() {
	key := w.GetCcsKeyPath() + `\Control\Terminal Server\fDenyTSConnections`
	w.SetRegistry(key, "0", `REG_DWORD`)
	key = w.GetCcsKeyPath() + `\Services\MpsSvc\Start`
	w.SetRegistry(key, "3", `REG_DWORD`)
	// turn off Windows Firewall completely
	for _, prof := range []string{
		"StandardProfile", "PublicProfile", "DomainProfile",
	} {
		key = w.GetCcsKeyPath() + `\Services\SharedAccess\Parameters\FirewallPolicy\` + prof + `\EnableFirewall`
		w.SetRegistry(key, "0", `REG_DWORD`)
	}
}

func (w *SWinRegTool) ResetUSBProfile() {
	// https://www.kraxel.org/blog/2014/03/qemu-and-usb-tablet-cpu-consumtion/
	// reset USB registry
	key := w.GetCcsKeyPath() + `\Control\usbflags`
	w.DelRegistry(key)
	key = w.GetCcsKeyPath() + `\Enum\USB`
	w.DelRegistry(key)
}
