#!/usr/bin/python
# -*- coding: UTF-8 -*-
###########################################################################
# winewrite.py - description                                             #
# ------------------------------                                          #
# begin     : Fri Mar 26 2004                                             #
# copyright : (C) 2006 by Yuriy Kozlov                                    #
# email     : yuriy.kozlov@gmail.com                                      #
#                                                                         #
###########################################################################
#                                                                         #
#   This program is free software; you can redistribute it and/or modify  #
#   it under the terms of the GNU General Public License as published by  #
#   the Free Software Foundation; either version 2 of the License, or     #
#   (at your option) any later version.                                   #
#                                                                         #
###########################################################################

import os
import wineread
import random

""" Provides functions for changings settings in wine """

def SetDriveMappings(drives):
    """ Sets wine's drive settings """
    driveletters = os.listdir(wineread.winepath + "/dosdevices")
    set(driveletters)
    
    for drive in drives[:26]:
        letter = drive[1].lower()
        defineDrive = False
        if letter in driveletters:	# The drive exists
            if drive[2]:    # The drive is in use
                # Compare for changes
                changed = False
                # Check if the mapping changed
                if drive[2] != os.readlink(wineread.winepath + "/dosdevices/" + letter):
                    changed = True
                        
                # If it's changed, it will be recreated
                if changed:
                    os.unlink(wineread.winepath + "/dosdevices/" + letter)
                    defineDrive = True
            else:
                # Remove the drive
                os.unlink(wineread.winepath + "/dosdevices/" + letter)
        else:	# The drive doesn't exist
            if drive[2]:    # The drive is in use
                # Create it
                defineDrive = True
            else:
                # Do nothing
                continue
            
        if defineDrive:
            os.symlink(drive[2], wineread.winepath + "/dosdevices/" + letter)
            
    SetDriveTypes(drives[:26])
    SetShellLinks(drives[26:])
            
def SetShellLinks(shelllinks):
    existingshelllinks = os.listdir(wineread.winepath + "/dosdevices/c:/users/" + os.environ['USER'])
    set(existingshelllinks)
    shellregistry = wineread.GetShellRegistry()
    
    for link in shelllinks:
        createLink = False
        if link[1] in existingshelllinks:	# The link exists
            linkpath = wineread.winepath + "/dosdevices/c:/users/" + os.environ['USER'] + "/" + link[1]
            if link[2]:    # The folder is mapped
                # Compare for changes
                changed = False
                # Check if the mapping changed
                if os.path.islink(linkpath) and link[2] != os.readlink(linkpath):
                    changed = True
                elif not os.path.islink(linkpath) and link[2] != linkpath:
                    changed = True
                elif link[5] != shellregistry.get(link[1], wineread.defaultwinfolderspath + "\\" + link[1]):
                    changed = True
                        
                # If it's changed, it will be recreated
                if changed:
                    if os.path.islink(linkpath):
                        os.unlink(linkpath)
                    else:
                        os.rename(linkpath,linkpath + "-backup" + str(random.randint(1,1000000)))
                    createLink = True
            else:
                # Remove the link
                os.unlink(linkpath)
        else:	# The link doesn't exist
            if link[2]:    # The folder is mapped
                # Create it
                createLink = True
            else:
                # Do nothing
                continue
            
        if createLink:
            os.symlink(link[2], wineread.winepath + "/dosdevices/c:/users/" + os.environ['USER'] + "/" + link[1])
            if link[1] in shellregistry:
                SetShellRegistry(link)
                
                
def SetShellRegistry(link):
    shellfile=open('.registryshellw.reg','w')
    shellfile.write("REGEDIT4\n\n[HKEY_USERS\\.Default\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders]\n")
    
    link[5] = link[5].replace("\\","\\\\")
    shellfile.write('"' + link[1] + '"="' + link[5] + '"\n')
    
    shellfile.write("\n[HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders]\n")
    
    link[5] = link[5].replace("\\","\\\\")
    shellfile.write('"' + link[1] + '"="' + link[5] + '"\n')
    
    shellfile.write("\n[HKEY_USERS\\.Default\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders]\n")
    
    shellfile.write('"' + link[1] + '"="' + "%USERPROFILE%\\\\" + link[1] + '"')
    
    shellfile.write("\n[HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders]\n")
    
    shellfile.write('"' + link[1] + '"="' + "%USERPROFILE%\\\\" + link[1] + '"')
    shellfile.close()
    
    os.system("wine regedit .registryshellw.reg")
    os.remove(".registryshellw.reg")
            
def SetKeyValues(key,settings):
    """ Sets all the values in key to those from the dictionary settings """
    file=open('.registrykey.reg','w')
    file.write("REGEDIT4\n\n[" + key + "]\n")
    
    for setting in settings:
        # Casting to a python string is necessary for older versions of PyTQt
        if str(settings[setting])[:4] == 'hex:':
            file.write('"'+str(setting)+'"='+str(settings[setting])+'\n')
        else:
            file.write('"'+str(setting)+'"="'+str(settings[setting])+'"\n')
        
    file.close()
    os.system("wine regedit .registrykey.reg")
    os.remove(".registrykey.reg")
    
def SetValue(key,value,data):
    """ Sets the value in key to data """
    file=open('.registryvalue.reg','w')
    file.write("REGEDIT4\n\n[" + key + "]\n")
    file.write('"' + value + '"="' + data + '"')
    file.close()
    
    os.system("wine regedit .registryvalue.reg")
    os.remove(".registryvalue.reg")

def SetDriveTypes(drives):
    """ Sets the type for the drives in the registry """
    drivesfile=open('.registrydrives.reg','w')
    drivesfile.write("REGEDIT4\n\n[HKEY_LOCAL_MACHINE\\Software\\Wine\\Drives]\n")
    
    for drive in drives:
        mapping = drive[2]
        if mapping:
            drivesfile.write('"' + drive[1] + '"="' + drive[3] + '"\n')
            
    drivesfile.close()
    
    os.system("wine regedit .registrydrives.reg")
    os.remove(".registrydrives.reg")
    
def SetAudioDriver(driver):
    """ Sets the audio driver in the registry """
    SetValue("HKEY_CURRENT_USER\\Software\\Wine\\Drivers","Audio",driver)
    
def SetDSoundSettings(settings, app = None):
    """ Sets the settings for Direct Sound in the registry """
    if not app:
        SetKeyValues("HKEY_CURRENT_USER\\Software\\Wine\\DirectSound", settings)
    else:
        SetKeyValues("HKEY_CURRENT_USER\\Software\\Wine\\AppDefaults\\" +\
            app + "\\DirectSound", settings)
    
def SetWindowSettings(settings, app = None):
    """ Sets the window settings in the registry """
    windowsfile=open('.registrywindows.reg','w')
    if not app:
        windowsfile.write("REGEDIT4\n\n[HKEY_CURRENT_USER\\Software\\Wine\\X11 Driver]\n")
    else:
        windowsfile.write("REGEDIT4\n\n[HKEY_CURRENT_USER\\Software\\Wine\\AppDefaults\\" +\
            app + "\\X11 Driver]\n")
    
    # There is a bug in wine that doesn't allow removing of registry entries from
    # a reg file, so unchecking emulate desktop can't be implemented this way yet.
        
    for setting in settings:
        if settings[setting]:
            windowsfile.write('"'+str(setting)+'"="'+str(settings[setting])+'"\n')
        else:
            # winecfg removes the value when the emulate desktop checkbox is unchecked
            windowsfile.write('"'+str(setting)+'"=-\n')
        
    windowsfile.close()
    os.system("wine regedit .registrywindows.reg")
    os.remove(".registrywindows.reg")
    
def SetD3DSettings(settings, app = None):
    """ Sets the settings for Direct3D in the registry """
    if not app:
        SetKeyValues("HKEY_CURRENT_USER\\Software\\Wine\\Direct3D", settings)
    else:
        SetKeyValues("HKEY_CURRENT_USER\\Software\\Wine\\AppDefaults\\" +\
            app + "\\Direct3D", settings)
    
def SetDesktopSettings(settings):
    """ Sets the control panel \ Desktop settings in the registry """
    SetKeyValues("HKEY_CURRENT_USER\\Control Panel\\Desktop", settings)
    
def SetWinVersion(version, app = None):
    """ 
    Sets the windows version in the registry
    Sample format for version:
    ( "winxp",   "Windows XP",     5,  1, 0xA28, "VER_PLATFORM_WIN32_NT", "Service Pack 2", 2, 0, "WinNT")
    """
    winverfile=open('.registrywinver.reg','w')
    if not app:
        winverfile.write("REGEDIT4\n\n[HKEY_CURRENT_USER\\Software\\Wine]\n")
        winverfile.write('"Version"="' + version[0] + '"\n')
        
        Key9x = "\n[HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows\\CurrentVersion]\n"
        KeyNT = "\n[HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion]\n"
        KeyProdNT = "\n[HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\ProductOptions]\n"
        KeyWindNT = "\n[HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Windows\n"
        KeyEnvNT  = "\n[HKEY_LOCAL_MACHINE\\System\\CurrentControlSet\\Control\\Session Manager\\Environment]\n"
        
        versionnumber9x = str(version[2]) + '.' + str(version[3]) + '.' + str(version[4])
        versionnumberNT = str(version[2]) + '.' + str(version[3])
        
        if version[5] == "VER_PLATFORM_WIN32_WINDOWS":
            winverfile.write(Key9x + '"VersionNumber"="' + versionnumber9x + '"\n')
            winverfile.write(Key9x + '"SubVersionNumber"="' + str(version[6]) + '"\n')
            
            winverfile.write(KeyNT + '"CSDVersion"=-\n')
            winverfile.write(KeyNT + '"CurrentVersion"=-\n')
            winverfile.write(KeyNT + '"CurrentBuildNumber"=-\n')
            winverfile.write(KeyProdNT + '"ProductType"=-\n')
            winverfile.write(KeyWindNT + '"CSDVersion"=-\n')
            winverfile.write(KeyEnvNT + '"OS"=-\n')
        elif version[5] == "VER_PLATFORM_WIN32_NT":
            winverfile.write(KeyNT + '"CurrentVersion"="' + versionnumberNT + '"\n')
            winverfile.write(KeyNT + '"CSDVersion"="' + str(version[6]) + '"\n')
            winverfile.write(KeyNT + '"CurrentBuildNumber"="' + str(version[4]) + '"\n')
            winverfile.write(KeyProdNT + '"ProductType"="' + str(version[9]) + '"\n')
            winverfile.write(KeyWindNT + '"CSDVersion"=dword:00000' + str(version[7]) + '00\n')
            winverfile.write(KeyEnvNT + '"OS"="Windows_NT"\n')
            
            winverfile.write(Key9x + '"VersionNumber"=-\n')
            winverfile.write(Key9x + '"SubVersionNumber"=-\n')
        elif version[5] == "VER_PLATFORM_WIN32s":
            winverfile.write(Key9x + '"VersionNumber"=-\n')
            winverfile.write(Key9x + '"SubVersionNumber"=-\n')
            winverfile.write(KeyNT + '"CSDVersion"=-\n')
            winverfile.write(KeyNT + '"CurrentVersion"=-\n')
            winverfile.write(KeyNT + '"CurrentBuildNumber"=-\n')
            winverfile.write(KeyProdNT + '"ProductType"=-\n')
            winverfile.write(KeyWindNT + '"CSDVersion"=-\n')
            winverfile.write(KeyEnvNT + '"OS"=-\n')
    else:
        winverfile.write("REGEDIT4\n\n[HKEY_CURRENT_USER\\Software\\Wine\\AppDefaults\\" +\
            app + "]\n")
        if version[0] == "global":
            winverfile.write('"Version"=-\n')
        else:
            winverfile.write('"Version"="' + version[0] + '"\n')
        
    winverfile.close()
    
    os.system("wine regedit .registrywinver.reg")
    os.remove(".registrywinver.reg")
    
def SetApps(apps):
    """ Adds and removes keys for app specific settings for apps """
    oldapps = wineread.GetApps()
    newapps = []
    
    # Add new app keys
    for app in apps:
        if app not in oldapps:
            newapps.append(app)
    AddApps(newapps)
    
    # Remove removed app keys
    for app in oldapps:
        if app not in apps:
            RemoveApp(app)
            
def RemoveApp(app):
    """ Removes the key for settings for app """
    os.system("wine regedit /D HKEY_USERS\\\\S-1-5-4\\\\Software\\\\Wine\\\\AppDefaults\\\\" +\
        app)
        
def AddApps(apps):
    """ Adds a key for app """
    appsfile=open('.registryapps.reg','w')
    appsfile.write("REGEDIT4\n\n")
    
    for app in apps:
        appsfile.write('[HKEY_CURRENT_USER\\Software\\Wine\\AppDefaults\\' +\
            app + ']\n')
        
    appsfile.close()
    os.system("wine regedit .registryapps.reg")
    os.remove(".registryapps.reg")
    
def SetDllOverrides(overrides, app = None):
    """ Sets the dll override settings in the registry """
    dllfile=open('.registrydll.reg','w')
    if not app:
        dllfile.write("REGEDIT4\n\n[HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides]\n")
    else:
        dllfile.write("REGEDIT4\n\n[HKEY_CURRENT_USER\\Software\\Wine\\AppDefaults\\" +\
            app + "\\DllOverrides]\n")
        
    origoverrides = wineread.GetDllOverrides(app)
    
    for dll in list(overrides.keys()):
        dllfile.write('"'+str(dll)+'"="'+str(overrides[dll])+'"\n')
        
    for dll in list(origoverrides.keys()):
        if dll not in overrides:
            dllfile.write('"'+str(dll)+'"=-\n')
        
    dllfile.close()
    os.system("wine regedit .registrydll.reg")
    os.remove(".registrydll.reg")
    
def SetDefaultBrowser(browser):
    """
    Sets the default browser to browser
    Doesn't set windows browsers, leaves it for the program to do.
    """
    file=open('.registrybrowser.reg','w')
    file.write("REGEDIT4\n")
    
    if browser[1] == ':':
        for format in wineread.default_browser_formats:
            file.write("\n[HKEY_LOCAL_MACHINE\\Software\\Classes\\" +\
                format + "\\shell\\open\\command]\n")
            file.write('@="' + browser + '"\n')
        file.close()
    
        os.system("wine regedit .registrybrowser.reg")
        os.remove(".registrybrowser.reg")
    else:   # winebrowser
        for format in wineread.default_browser_formats:
            file.write("\n[HKEY_LOCAL_MACHINE\\Software\\Classes\\" +\
                format + "\\shell\\open\\command]\n")
            file.write('@="winebrowser"\n')
        file.close()
    
        os.system("wine regedit .registrybrowser.reg")
        os.remove(".registrybrowser.reg")
        
        SetFirstBrowser(browser)
        
def SetDefaultMailer(mailer):
    """
    Sets the default mailer to mailer
    Doesn't set windows mailers, leaves it for the program to do.
    """
    file=open('.registrymailer.reg','w')
    file.write("REGEDIT4\n")
    
    if mailer[1] == ':':
        for format in wineread.default_mailer_formats:
            file.write("\n[HKEY_LOCAL_MACHINE\\Software\\Classes\\" +\
                format + "\\shell\\open\\command]\n")
            file.write('@="' + mailer + '"\n')
        file.close()
    
        os.system("wine regedit .registrymailer.reg")
        os.remove(".registrymailer.reg")
    else:   # winebrowser
        for format in wineread.default_mailer_formats:
            file.write("\n[HKEY_LOCAL_MACHINE\\Software\\Classes\\" +\
                format + "\\shell\\open\\command]\n")
            file.write('@="winebrowser %1"\n')
        file.close()
    
        os.system("wine regedit .registrymailer.reg")
        os.remove(".registrymailer.reg")
        
        SetFirstMailer(mailer)
    
def SetFirstBrowser(browser):
    """ Sets the first in the list of browsers for winebrowser to use to browser """
    originalbrowserlist = wineread.GetNativeBrowserList()
    
    if browser in originalbrowserlist:
        originalbrowserlist.remove(browser)
    browserlist = [browser] + originalbrowserlist
        
    browserlist = str(browserlist).strip('[]')
    browserlist = browserlist.replace("'","")
    browserlist = browserlist.replace(", ",",")
    
    SetValue("HKEY_CURRENT_USER\\Software\\Wine\\WineBrowser","Browsers",browserlist)
    
def SetFirstMailer(mailer):
    """ Sets the first in the list of mailers for winebrowser to use to mailer """
    originalmailerlist = wineread.GetNativeMailerList()
        
    if mailer in originalmailerlist:
        originalmailerlist.remove(mailer)
    mailerlist = [mailer] + originalmailerlist
    
    mailerlist = str(mailerlist).strip('[]')
    mailerlist = mailerlist.replace("'","")
    mailerlist = mailerlist.replace(", ",",")
    
    SetValue("HKEY_CURRENT_USER\\Software\\Wine\\WineBrowser","Mailers",mailerlist)
    
def CreateWineDrive(path = None):
    """
    Creates a fake windows installation in path
    """
    if not path:
        path = wineread.default_winepath
    
    os.system("WINEPREFIX=" + path + " winepath --wait")
    
# ----- Theming -----
            
def SetCurrentTheme(theme):
    """
    Sets the current theme
    theme = (theme,color,size), None if none is set
    """
    if not theme:
        theme = ("", "", "")
        
    themesettings = {"ColorName":theme[1],
        "SizeName":theme[2],
        "ThemeActive":"1"}
        
    if not theme[0]:
        themesettings["DllName"] = ""
        themesettings["ThemeActive"] = "0"
    else:
        themesettings["DllName"] = "C:\\\\windows\\\\Resources\\\\Themes\\\\" +\
            theme[0] + "\\\\" + theme[0] +".msstyles"
        
    themefile=open('.registrytheme.reg','w')
    themefile.write("REGEDIT4\n\n[HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager]\n")
    for setting in themesettings:
        if themesettings[setting]:
            themefile.write('"'+str(setting)+'"="'+str(themesettings[setting])+'"\n')
        else:
            themefile.write('"'+str(setting)+'"=-\n')
        
    themefile.close()
    os.system("wine regedit .registrytheme.reg")
    os.remove(".registrytheme.reg")
    
def SetColorSettings(colors):
    """ Takes a dictionary of color settings and sets them in the registry """
    SetKeyValues("HKEY_CURRENT_USER\\Control Panel\\Colors",colors)
    SetKeyValues("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager\\Control Panel\\Colors",colors)

def SetWindowMetrics(metrics):
    """
    Takes a dictionary of WindowMetrics settings and sets them in the registry
    """
    SetKeyValues("HKEY_CURRENT_USER\\Control Panel\\Desktop\\WindowMetrics",metrics)

ports_translation = {"lp":"lpt","ttyS":"com"}

def CreatePorts(ports = None):
    """
    Creates links to ports in dosdevices
    """
    if not ports:
        # Find ports in /dev
        ports = ["lp0"]
    
    for port in ports:
        winport = ports_translation[port.rstrip("012345678")] +\
            str(int(port.lstrip("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")) + 1)
        os.symlink("/dev/" + port, wineread.winepath + "/dosdevices/" + winport)
    
