#!/usr/bin/python

# copyright 2007 ETH Zurich, DMATL
# author lorenz textor

import os
import sys
from urllib import urlopen
import time

repositoryPath = '/wcms/zopesites/Silva-1.5/var/repository/'    # path to repository (as written in assetsListFile)
backupPath = '/wcms/zopesites/repository_backup/'               # path where asset orphans are moved to
assetsListFile = '/tmp/assets.txt'                              # each asset path on one line (can be generated using AssetsListing.py in /silva/ETH/assets_listing)
logFile = './move_log.txt'                                      # leave blank for no log


def repositoryFiles(dir):
    files = []
    dirs = []
    def printall(junk, dirpath, namelist):
        for name in namelist:
            fullname = os.path.normpath(os.path.join(dirpath,name))
            if os.path.isfile(fullname):
                files.append(fullname)
            elif os.path.isdir(fullname):
                dirs.append(fullname)
    os.path.walk(dir, printall, None)
    return (files, dirs)

def silvaAssets(path):
    assets = {}
    f = file(assetsListFile)
    for line in f:
        assets[line.strip()] = 1
    return assets.keys()  # get unique array

def getSizeOfFiles(files):
    size = 0
    for f in files:
        size += os.path.getsize(f)
    size = float(size)
    kb = size/1024
    if kb < 1:
        return '%.2f Bytes' % size
    else:
        mb = kb/1024
        if mb < 1:
            return '%.2f KB' % kb
        else:
            gb = mb/1024
            if gb < 1:
                return '%.2f MB' % mb
            else:
                return '%.2f GB' % gb
    return size

def moveFiles(files, oldPath, newPath):
    # TODO chown to zope:zope afterwards (in case of removeToBackup)
    if oldPath[-1:]!='/':
        oldPath += '/'
    log = ['\n\nmoved files from %s to %s on %s' % (oldPath, newPath, time.asctime())]
    i = 0
    for f in files:
        showProgress('Moving files:', i, len(files))
        suffix = f[len(oldPath):]
        if suffix[:1]=='/':
            suffix = suffix[1:] # be sure that there are no absolute paths
        mvPath = os.path.join(newPath, suffix)
        log.append('move %s to %s' % (f, mvPath))
        os.renames(f, mvPath)
        i += 1
    if logFile:
        lf = file(logFile,'a')
        lf.write('\n'.join(log))
        lf.close()

def recreateFolderStructure(dirs):
    # TODO chown to zope:zope afterwards
    log = ['\n\nrecreated folder structure on %s' % (time.asctime())]
    i = 0
    for d in dirs:
        showProgress('Recreating folder structure:', i, len(dirs))
        if not os.path.isdir(d):
            log.append('create %s' % (d))
            os.makedirs(d)
        i += 1
    if logFile:
        lf = file(logFile,'a')
        lf.write('\n'.join(log))
        lf.close()

def removeFiles(files):
    log = ['\n\ndeleted .undo files on %s' % time.asctime()]
    i = 0
    for f in files:
        showProgress('Deleting files:', i, len(files))
        log.append('delete %s' % f)
        os.remove(f)
        i += 1
    if logFile:
        lf = file(logFile,'a')
        lf.write('\n'.join(log))
        lf.close()

def removeEmptyDirectories(dirs):
    log = ['\n\ndeleted empty directories on %s' % time.asctime()]
    i = 0
    for f in dirs:
        showProgress('Deleting empty directories:', i, len(dirs))
        if not os.listdir(f):
            log.append('delete %s' % f)
            os.removedirs(f)
        i += 1
    if logFile:
        lf = file(logFile,'a')
        lf.write('\n'.join(log))
        lf.close()
    

def showProgress(prefix, now, total):
    global percentOld
    percent = (now+1)*50/total
    if percent != percentOld:
        output = '%s%s[%s%s]' % (prefix, (30-len(prefix))*' ', percent*'#', (50-percent)*'.')
        if percent==50:
            print output
        else:
            print output+'\r',
            sys.stdout.flush()
        percentOld = percent

def removeOrphans():
    print DarkRed
    print '[WARNING]\nThis script also removes thumbnails and web representations of images!\nTo recreate these images run the script ImageFixer.py in /silva/ETH/image_webscale_fixer afterwards.'
    print ResetColor
    (files,dirs) = repositoryFiles(repositoryPath)
    print '%d files in repository.' % len(files)
    assets = silvaAssets(assetsListFile)
    print '%d assets in silva.' % len(assets)
    orphans = []
    undoFiles = 0
    i = 0
    for f in files:
        showProgress('Checking files:', i, len(files))
        if f not in assets:
            orphans.append(f)
            if f[-5:]=='.undo':
                undoFiles += 1
        i += 1
    print '%d orphans in repository (%s). %d of them are .undo files.' % (len(orphans), getSizeOfFiles(orphans), undoFiles)
    if raw_input('Show files? (y/N) ')=='y':
        print '\n'.join(orphans)
    if raw_input('Move files to backup (existing files will be overwritten)? (y/N) ')=='y':
        moveFiles(orphans, repositoryPath, backupPath)
        recreateFolderStructure(dirs)  # necessary because otherwise thumbnails cannot be created for some images
    print DarkRed
    print "[WARNING]\nBe sure to set owner of repository back to zope:zope if you haven't run this script as user zope!"
    print ResetColor
    print 'Bye...'

def removeUndos():
    (files,dirs) = repositoryFiles(repositoryPath)
    undoFiles = []
    i = 0
    for f in files:
        showProgress('Checking files:', i, len(files))
        if f[-5:]=='.undo':
            undoFiles.append(f)
        i += 1
    print '%d .undo files in repository (%s).' % (len(undoFiles), getSizeOfFiles(undoFiles))
    if raw_input('Show files? (y/N) ')=='y':
        print '\n'.join(undoFiles)
    if raw_input('Delete files? (y/N) ')=='y':
        removeFiles(undoFiles)
        #removeEmptyDirectories(dirs)  # breaks a lot of things (impossible to create some thumbnails afterwards) -> perhaps ok when run after all thumbnails have been recreated
    print 'Bye...'

def returnToBackup():
    if raw_input('Move files from backup to repository (existing files will be overwritten)? (y/N) ')=='y':
        (files,dirs) = repositoryFiles(backupPath)
        moveFiles(files, backupPath, repositoryPath)
        print DarkRed
        print "[WARNING]\nBe sure to set owner of repository back to zope:zope if you haven't run this script as user zope!"
        print ResetColor
    print 'Bye...'


percentOld = None
ESC = chr(27)
DarkRed = ESC + "[31;2m"
ResetColor = ESC + "[0m"

choose = raw_input('\n1 Delete undo files\n2 Delete orphan files\n3 Return to backup\n4 Quit\n\nYour choice: ')
if choose=='1':
    removeUndos()
elif choose=='2':
    removeOrphans()
elif choose=='3':
    returnToBackup()
else:
    print 'Bye...'
