#!/usr/bin/python2

import os
import os.path
import commands
import sys
import ConfigParser
import getopt
import cPickle
import zlib
import string
import time

from commondic import *

def exit( message ) :
    print message
    sys.exit( 1 )

def printHeader() :
    if catalog.longList == 1 :
        print 'Size                  Date      Name'
        print '=====================-=========-=============================================='
    else :
        print 'Name'
        print '=============================================='

def fileString( disk, file ):
    if catalog.longList == 1 :
        return string.rjust( catalog.fancyNumbers( file.size ), 15 ) + ' bytes ' + \
            string.ljust( time.strftime( '%x', time.localtime( file.time ) ), 9 ) + ' ' + \
            string.ljust( disk + file.name, 46 )
    else :
        return string.ljust( disk + file.name, 46 )

def showDisk( diskName ):
    try:
        disk = catalog.loadDisk( diskName )
        printHeader()
        for file in disk.files:
            print fileString( disk.name, file )
    except DicNoSuchDiskException, details :
        exit( 'Disk not found : ' + details )
    except DicCorruptDiskException :
        exit( 'Disk corrupted : ' + details )

def searchInDisks( content, disks ):
    printHeader()
    if len( disks ) == 0 :
        disks = catalog.diskNames()
    try :
        foundFiles = catalog.search( disks, content )
    except DicNoSuchDiskException, details :
        exit( 'Disk not found : ' + details )
    except DicCorruptDiskException :
        exit( 'Disk corrupted : ' + details )
    for file in foundFiles:
        print fileString( file.diskName, file )

    if catalog.getFoundFiles :
        fileNames = []
        for file in foundFiles :
            fileNames.append( file.diskName + file.name )
        getFiles( fileNames )

# Guess name of disk:
# 1. if only one file exists on the disk (like movie-cds), use it as
#    disk-name, but without extension
# 2. other ideas?
# ...
# last: return empty string
def guessDiskName( disk ):
    if len( disk.files ) == 1 :
        lastDot = string.rfind( disk.files[ 0 ].name, '.' )
        if lastDot == -1 :
            name = disk.files[ 0 ].name[ 1 : ]
        else :
            name = disk.files[ 0 ].name[ 1 : lastDot ]
    elif os.name == "posix":
        device_file = catalog.devices[catalog.currentDevice].getDeviceFile()
        if device_file:
            fp = open(device_file)
            fp.seek(32808)
            label = fp.read(32)
            fp.close()
            return label.strip()
    else:
        name = ''
    return name

def addDisk( name ):
    device = catalog.currentDevice
    try :
        path = catalog.devices[device]
    except KeyError :
        exit( 'No such device' )
    if catalog.devices[device].runMount == 1:
        try:
            print 'mounting', device, 'to', catalog.devices[device].path
            catalog.devices[device].mount()
        except DicMountException,details:
            exit( details )
    disk = Disk( '' )
    disk.category = catalog.defaultCategory
    disk.status = catalog.defaultStatus
    disk.device = catalog.currentDevice
    print 'Reading disk...'
    disk.readDirs( catalog.devices[ device ].path )
    print 'Done.'
    if ( name == '' ):
        guessedName = guessDiskName( disk )
        while 1 :
            print 'Please enter a name for this disk: [' + guessedName + ']'
            try :
                name = raw_input( '' )
            except KeyboardInterrupt :
                exit( 'exiting.' )
            if name == '' :
                disk.name = guessedName
            else:
                disk.name = name
            if disk.name == '' :
                print 'Diskname can\'t be empty'
            else :
                break
    else :
        disk.name = name
    if catalog.categoryIsSpecified == 0 :
        # ask for a category
        print 'Please enter the category of this disk: [' + catalog.defaultCategory + ']'
        try:
            category = raw_input( '' )
        except KeyboardInterrupt:
            exit( 'exiting.' )
        if category != '':
            disk.category = category
    catalog.saveDisk( disk )

    if catalog.devices[device].runMount == 1:
        try:
            print 'umounting', device
            catalog.devices[device].umount()
        except DicUmountException, details:
            exit( details )

# lists all available disks
def listDisks():
    # print header
    if catalog.longList == 1 :
        print 'Size                  Date      Name                 Category     Status'
        print '=====================-=========-====================-============-============'
    else :
        print 'Name                 Category     Status'
        print '====================-============-============'
    for diskName in catalog.diskNames() :
        disk = Disk( diskName )
        disk.loadInfo( catalog.catalogPath )
        if catalog.longList == 1 :
            print string.rjust( catalog.fancyNumbers( disk.size ), 15 ) + ' bytes ' + \
                string.ljust( time.strftime( '%x', time.localtime( disk.time ) ), 9 ) + ' ' + \
                string.ljust( diskName, 20 ) + ' ' + string.ljust( disk.category, 13 ) + ' ' + \
                string.ljust( disk.status, 12 )
        else :
            print string.ljust( diskName, 20 ) + ' ' + string.ljust( disk.category, 13 ) + ' ' + \
                string.ljust( disk.status, 12 )

def updateDisk( diskName, newDiskName ) :
    try :
        catalog.updateDisk( diskName, newDiskName )
    except DicNoSuchDiskException, details :
        exit( 'Disk not found : ' + details )
    except DicCorruptDiskException :
        exit( 'Disk corrupted : ' + details )

def printMessageAndWait( message ) :
    print message
    try :
        enter = raw_input( '' )
    except KeyboardInterrupt :
        catalog.exit( 'exiting.' )

def printMessage( message ) :
    print message

def getFiles( files ) :
    catalog.getFiles( files, '.' )

def showUsage():
    print "dic", VERSION
    print """
Usage : dic [options] command

	dic is a simple command line DIsk-Catalogizer.

Commands:
    add     [<diskname>]                - add a new disk to the catalog
    search  <string or regexp>          - search files in the catalog
    remove  <diskname> [<diskname>]...  - remove a disk from the catalog
    get     <filename> [<filename>]...  - copy files from disks
    show    <diskname>                  - show the contents of a disk
    list                                - list disknames
    update  <diskname> [<newname>]      - update a disk (to change status, category, or rename)
    view    <filename>                  - view the filtered infos of a file

Options:
    -h or --help               this help text
    -i or --case-sensitive     case-sensitive search
    -d or --device             device to use
    -r or --regexp             search with regular expression
    -l or --long               long list for files or disks ( with date, size, etc. )
    -g or --get                copy found files to the current directory
    -c or --category           specify category
    -s or --status             specify status
    -m or --mode               specify searchmode ( 0, 1, 2 )
                                 0: search in filenames (default)
                                 1: search in files' contents
                                 2: search both in filenames and contents

"""

def removeDisks( diskNames ):
    for diskName in diskNames:
        catalog.removeDisk( diskName )

def viewFilterInfos( fileName ) :
    print catalog.viewFilterInfos( params[ 0 ] )

# main
if __name__ == '__main__':

    try:
        catalog = Catalog()
    except DicNoDeviceInConfigException:
        exit( 'No devices found, please check your config-files. (/etc/dic.conf and/or $HOME/.dic/dic.conf)' )
    opts, args = getopt.getopt( sys.argv[ 1 : ], 'irld:ghvc:s:m:', [ 'case-sensitive', 'regexp', 'long', 'device=', 'get', 'help', 'version', 'category=', 'status=', 'mode=' ] )

    catalog.printMessageAndWait = printMessageAndWait
    catalog.printMessage = printMessage
    catalog.exit = exit

    for o, a in opts :
        if o == '-i' or o == '--case-sensitive' :
            catalog.caseSensitiveSearch = 1
        if o == '-r' or o == '--regexp' :
            catalog.regexpSearch = 1
        if o == '-l' or o == '--long' :
            catalog.longList = 1
        if o == '-d' or o == '--device':
            catalog.deviceIsSpecified = 1
            catalog.currentDevice = a
        if o == '-g' or o == '--get':
            catalog.getFoundFiles = 1
        if o == '-c' or o == '--category' :
            catalog.categoryIsSpecified = 1
            catalog.currentCategory = a
        if o == '-s' or o == '--status' :
            catalog.statusIsSpecified = 1
            catalog.currentStatus = a
        if o == '-m' or o == '--mode' :
            catalog.searchMode = a

    if catalog.deviceIsSpecified != 1 :
        catalog.currentDevice = catalog.defaultDevice
    if len( args ) == 0:
        showUsage()
        sys.exit( 0 )
    else:
        if len( args ) == 1:
            params = [ '' ]
        else:
            params = args[ 1 : ]
    if args[ 0 ] == 'add':
        addDisk( params[ 0 ] )
    elif args[ 0 ] == 'search':
        searchInDisks( params[ 0 ], params[ 1 : ] )
    elif args[ 0 ] == 'remove':
        removeDisks( params )
    elif args[ 0 ] == 'get':
        getFiles( params )
    elif args[ 0 ] == 'show':
        showDisk( params[ 0 ] )
    elif args[ 0 ] == 'list':
        listDisks()
    elif args[ 0 ] == 'update':
        if params[ 0 ] == '' :
            for diskName in catalog.allDiskNames() :
                updateDisk( diskName, '' )
        elif len( params ) < 2 :
            updateDisk( params[ 0 ], '' )
        else :
            updateDisk( params[ 0 ], params[ 1 ] )
    elif args[ 0 ] == 'view':
        viewFilterInfos( params[ 0 ] )
    else:
        showUsage()
    sys.exit( 0 )
