# scrubber.pyw
#
# Author: Mike Driscoll
#
# Updated: 05/16/2007
#
# Deletes folders and files, ignores errors. The deletion functions
# run in a separate thread.


import wx
import os
import glob
import sys
import shutil
import time
import win32api

from threading import Thread

userid = win32api.GetUserName()

class ProfileScrubber(wx.App):
    def __init__(self, redirect=True, filename=None):
        wx.App.__init__(self, redirect, filename)
        
    def OnInit(self):
        self.frame = wx.Frame(None, -1, title='Profile Scrubber Beta 0.3', size=(400,500))
    
        panel = wx.Panel(self.frame, -1)

        # user list up-to-date as of 10/20/2006
        user_list = self.getProfileList()
        
        tempF = r'C:\Documents and Settings\%s\Local Settings\Temp' % userid
        tempIntF = r'C:\Documents and Settings\%s\Local Settings\Temporary Internet Files' % userid

        # Create the controls        
        descriptionLbl = wx.StaticText(panel, -1, ' Choose an option below:')
        font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)
        descriptionLbl.SetFont(font)
        genericPathLbl = wx.StaticText(panel, -1, 'Enter Path:')
        self.path = wx.TextCtrl(panel, -1, '', size=(500,-1))

        optionLbl = wx.StaticText(panel, -1, 'Other Folders to be Deleted:')
        optionLbl.SetFont(font)
        self.tempCkbx = wx.CheckBox(panel, -1, 'Temp', size=wx.DefaultSize)
        self.tempCkbx.SetValue(True)
        self.tempFilesCkbx = wx.CheckBox(panel, -1, 'Temporary Internet Files', size=wx.DefaultSize)
        self.tempFilesCkbx.SetValue(True)
        self.tempTxt = wx.TextCtrl(panel, -1, tempF, size=(500,-1))
        self.tempTxt.Disable()
        self.tempFilesTxt = wx.TextCtrl(panel, -1, tempIntF, size=(500,-1))
        self.tempFilesTxt.Disable()        
                
        useridLbl = wx.StaticText(panel, -1, 'Choose the user \n(if different):')
        self.user = wx.ComboBox(panel, -1, userid, None, (150, -1), user_list, wx.CB_DROPDOWN)
        self.user.Bind(wx.EVT_COMBOBOX, self.comboChoice)
        
        scrubBtn = wx.Button(panel, -1, 'Scrub')
        self.Bind(wx.EVT_BUTTON, self.scrub, scrubBtn)
        closeBtn = wx.Button(panel, -1, 'Close')
        self.Bind(wx.EVT_BUTTON, self.close, closeBtn)

        # create a checklistbox widget to list all the user profiles on the machine
        profLbl = wx.StaticText(panel, -1, 'Please choose what profiles to remove:')
        profLbl.SetFont(font)
        self.profile_list = self.getProfileList()
        self.profile_cblb = wx.CheckListBox(panel, -1, size=(100, -1), choices=self.profile_list)

        # delete button
        deleteBtn = wx.Button(panel, -1, 'Delete Profiles')
        self.Bind(wx.EVT_BUTTON, self.deleteProfile, deleteBtn)
        
        # Main sizer to hold all the lesser sizers
        mainSizer = wx.BoxSizer(wx.VERTICAL)
        mainSizer.Add(descriptionLbl)
        mainSizer.Add((10,10))
        
        # pathSizer holds the top set of widgets
        pathSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
        pathSizer.AddGrowableCol(1)
        pathSizer.Add(genericPathLbl, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
        pathSizer.Add(self.path, 0, wx.EXPAND)
        pathSizer.Add(useridLbl, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL)
        pathSizer.Add(self.user, 1)
        pathSizer.Add((10,10))
        pathSizer.Add((10,10))
        pathSizer.Add((10,10))
        pathSizer.Add((10,10))
        pathSizer.Add(optionLbl,0)
        pathSizer.Add((10,10))
        pathSizer.Add(self.tempCkbx,0)
        pathSizer.Add(self.tempTxt,1)
        pathSizer.Add(self.tempFilesCkbx,0)
        pathSizer.Add(self.tempFilesTxt,1)
                        
        # btnSizer (holds the scrub & close buttons)       
        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
        btnSizer.Add(scrubBtn)
        btnSizer.Add((20,20), 1)
        btnSizer.Add(closeBtn)
        pathSizer.Add((10,10))
        pathSizer.Add(btnSizer, 1, wx.ALIGN_CENTER)

        # Profile Sizer (holds the check box / combobox and its delete button)
        profSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
        profSizer.Add(profLbl, 0)
        profSizer.Add((10,10))
        profSizer.Add(self.profile_cblb, 0)
        profSizer.Add((10,10))
        profSizer.Add(deleteBtn, 0)

        # Add the pathSizer to mainSizer        
        mainSizer.Add(pathSizer, 0, wx.EXPAND|wx.ALL, 10)
        mainSizer.Add(profSizer, 0, wx.EXPAND|wx.ALL, 10)
        panel.SetSizer(mainSizer)
        mainSizer.Fit(self.frame)
        mainSizer.SetSizeHints(self.frame)

        # initialize the thread
        self.iniThread()

        # ---- Make the app visible / OnInit requires a boolean "return" 
        self.frame.Show(True)
        return True

    def comboChoice(self, event):
        ''' On choice, change the two "Temp" directory paths to match the user choice. '''
        self.tempTxt.SetValue('')
        self.tempFilesTxt.SetValue('')
        new_user = event.GetString()
        self.tempTxt.AppendText(r'C:\Documents and Settings\%s\Local Settings\Temp' % new_user)
        self.tempFilesTxt.AppendText(r'C:\Documents and Settings\%s\Local Settings\Temporary Internet Files' % new_user)
            
    def scrub(self, event):
        ''' Delete the folders that the user has chosen. '''
        folders = []
        x = 0   #  Used to control what gets popped
        tempck = self.tempCkbx.GetValue()
        tempFiles_ck = self.tempFilesCkbx.GetValue()
        user_path = self.path.GetValue()
        paths = [self.path, self.tempTxt, self.tempFilesTxt]

        if tempck == False:
            paths.pop(1)
            x = 1
            
        if tempFiles_ck == False:
            if x:       # if true, then there's only 2 values, so pop the 2nd
                paths.pop(1)
            else:       # if false, there's 3 values, so pop the 3rd
                paths.pop(2)
        
        # Create a list of paths to be deleted
        for path in paths:
            if path.GetValue() != '':
                folders.append(path.GetValue())

        # If the user doesn't enter a path and unchecks both boxes, let the user know!
        if tempck == False and tempFiles_ck == False and user_path == '':
            dlg = wx.MessageDialog(None, 'You need to enter a path or check a checkbox to delete.',
                                   'Information', wx.OK | wx.ICON_INFORMATION)
            dlg.ShowModal()
            dlg.Destroy()
        
        # Get response code
        resCode = self.warningMessage(folders)
            
        # Delete the folder(s) if user chose "Yes"     
        if (resCode == wx.ID_YES):            
            t = time.ctime()
            print '**************************************************'
            print '\nNew Scrub Job accepted %s\n' % t
            print '**************************************************'
            FDeleteThread(self, folders)
       
    
    def warningMessage(self, folders):
        ''' Create a custom warning message for the user based on his choices. '''
        if len(folders) == 3:
            response = wx.MessageDialog(None, 'This will attempt to delete these folder\'s subfolders:\n\n%s\n%s\n%s\n\nIs this OK?' % (folders[0],folders[1],folders[2]),
                                            'WARNING', wx.YES_NO | wx.ICON_QUESTION)
            resCode = response.ShowModal()
            response.Destroy()
        elif len(folders) == 2:
            response = wx.MessageDialog(None, 'This will attempt to delete these folder\'s subfolders:\n\n%s\n%s\n\nIs this OK?' % (folders[0],folders[1]),
                                            'WARNING', wx.YES_NO | wx.ICON_QUESTION)
            resCode = response.ShowModal()
            response.Destroy()
        elif len(folders) == 1:
            response = wx.MessageDialog(None,'This will attempt to delete this folder\'s subfolders:\n\n%s\n\nIs this OK?' % (folders[0]),
                                            'WARNING', wx.YES_NO | wx.ICON_QUESTION)
            resCode = response.ShowModal()
            response.Destroy()
        else:
            pass            
        return resCode
    
    def getProfileList(self):
        ''' Search "Documents and Settings" folder and create a list of user profiles. '''
        userPaths = glob.glob(r'c:\documents and settings\\*')
        user_list = []
        for i in userPaths:
            if len(i[26:]) > 6:
		pass
	    elif i[26:].upper() == userid:
                pass
            else:
                user_list.append(i[26:])
        return user_list

    def deleteProfile(self, event):
        ''' Delete the profile(s). '''        

        prof_list = []
        count = 0
        resCode = ''
        prof_dir = r'C:\Documents and Settings'

        # Check if any profiles are checked and create a list of them.
        for i in self.profile_list:
            if self.profile_cblb.IsChecked(count):
                print '%s is checked' % i
                prof_list.append(i)
            else:
                print '%s is NOT checked' % i
            count += 1
            
        # Warn user about deleting profiles
        if len(prof_list) > 0:
            response = wx.MessageDialog(None, 'Do you really want to delete these profile(s)?',
                                                'WARNING', wx.YES_NO | wx.ICON_QUESTION)
            resCode = response.ShowModal()
            response.Destroy()

        # If "Yes" is chosen, delete the checked profiles    
        if resCode == wx.ID_YES:
            for x in prof_list:
                print prof_dir + '\\%s' % x
                #shutil.rmtree(prof_dir + '\\%s' % x, ignore_errors=True)
                #os.system(r'RD /S /Q "%s"' % (prof_dir + '\\%s' % x))
                subprocess.Popen(r'RD /S /Q "%s"' % (prof_dir + '\\%s' % x), shell=True)
            print 'Finished deleting selected profiles.'

        # Clear the combo-listbox
        self.profile_cblb.Clear()
        print 'cleared'
        self.profile_cblb.AppendItems(self.getProfileList())

    def iniThread(self):
        ''' Initialize thread object. '''
        
        ##### beginning of threading code setup #####
        # Set up event handler for any worker thread results
        EVT_RESULT(self,self.onResult)

        # And indicate we don't have a worker thread yet
        self.worker = None
        ###### end of threading code #######

    def onResult(self, event):
        ''' Reset the worker thread to None. '''       
        print 'Thread has finished!'
        self.worker = None
        
    def close(self, event):
        ''' Close the window '''
        self.frame.Close(True)


#####################################################################################
EVT_RESULT_ID = wx.NewId()

def EVT_RESULT(win, func):
    """Define Result Event."""
    win.Connect(-1, -1, EVT_RESULT_ID, func)
    
class ResultEvent(wx.PyEvent):
    """Simple event to carry arbitrary result data."""
    def __init__(self, data):
        """Init Result Event."""
        wx.PyEvent.__init__(self)
        self.SetEventType(EVT_RESULT_ID)
        self.data = data
    
class FDeleteThread(Thread):
    """Printer Child Thread Class."""
        
    def __init__(self, notify_window, fList):
        """Init Worker Thread Class."""
        Thread.__init__(self)
        self._notify_window = notify_window
        self._want_abort = 0        
        self.folders = fList
        self.start()    # start the thread

    def run(self):
        """Run Worker Thread."""
        for folder in self.folders:
                dirs = glob.glob(folder + '\\*')
                files = glob.glob(folder + '\\*.*')
                for d in dirs:
                    if os.path.isdir(d):                        
                        self.delete2(d)
                    # END IF
                # END INNER FOR LOOP
                for f in files:
                    try:
                        os.remove(f)
                    except:
                        print 'ERROR - Could not remove: %s' % f
        print 'Scrubbing finished!'
        wx.PostEvent(self._notify_window, ResultEvent(10))

    def delete2(self, item):                
        
        if os.path.isdir(item):
            try:
                print '\nDeleting %s' % item
                shutil.rmtree(item)
            except:
                #os.system(r'RD /S /Q "%s"' % item)
                subprocess.Popen(r'RD /S /Q "%s"' % item, shell=True)
        else:
            try:
                os.remove(item)
            except:
                #os.system('DEL /F /S /Q "%s"' % item)
                subprocess.Popen(r'DEL /F /S /Q  "%s"' % item, shell=True)

if __name__ == '__main__':
    app = ProfileScrubber()
    app.MainLoop()
