#!/Users/Ian/Desktop/PythonFiles/PyFiles/the-odds-api-client/oddsapienv/bin/python3
# Copyright (c) 2012, Dan Brooks
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# * Neither the name of the copyright holders nor the names of any
#   contributors may be used to endorse or promote products derived
#   from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.

# Last Modified [db] 2012.15.11
""" dl - moves files or directories to a "trash" directory """
__version__ = "0.1.0"

# Install Instructions
# --------------------
# 1. Copy this program to somewhere in your path (/usr/local/bin) 
# 2. Enable Permissions (chmod 755 /usr/local/bin/dl)
# 3. If you get an error about missing argparse, dl can install it for you or
#    you can install it yourself to /usr/local/lib/pymodules/

# TODO:
# Abide by http://standards.freedesktop.org/trash-spec/trashspec-0.8.html

import shutil   # Utility functions for copying and moving files
import os
import copy
import re

try:
    import argparse
except:
    # argparse Dependencies (must be absolute path)
    depends_path = "/usr/local/lib/pymodules"
    depends_server = "http://www.cs.uml.edu/~dbrooks/files/"
    import sys

    if not depends_path in sys.path and os.path.exists(depends_path+"/argparse.py"):
        # Path already exists - hopefully our stuff is still there, try 
        # adding it to the path and importing again
        sys.path.append(depends_path)
        import argparse
    elif os.getuid() == 0:
        # Path does not exist, but we are running as root so try to install
        print "dl: Requires missing module argparse. Please to install [y/n]? ",
        x = raw_input()
        if x.lower() == "y" or x.lower() == "yes":
            import urllib
            # Make Depends Directory structure
            try:
                os.makedirs(depends_path)
            except:
                pass
            finally:
                try:
                    os.chdir(depends_path)
                except:
                    print "dl: error could not get to %s"%depends_path
                    exit(0)
            # Get argparse
            try:
                urllib.urlretrieve(depends_server+"argparse.py",filename="argparse.py")
            except:
                print "dl: failed to contact server, aborting"
                exit(0)
            print "dl: Successfully installed dependencies! please re-run the command"
            exit(0)
        else:
            # We don't want to install dependencies, go away quitely
            exit(0)
    else:
        print "dl: Requires missing module argparse. Try re-running as 'sudo dl' to install"
        exit(0)
   

# Debuging flag
debugging = False


def archive(abspath):
    """ Moves the file indicated by an absolute path to an archive file
        of the next highest available number.
        >>> os.listdir("/home/user/")
        ['test.txt', 'test.txt.~1~']
        >>> archive_file("/home/user/test.txt")
        ['test.txt.~1~', 'test.txt.~2~']
    """
    name = os.path.basename(abspath)
    dirpath = os.path.dirname(abspath)
    
    # make sure file exists
    if not os.path.exists(abspath):
        raise OSError("dl: target file does not exists")
        

    def is_archive(thing):
        """ returns true if a file ends in .~#~ where # is some number """
        # \. and \~ escapes . and ~
        # ( ) means group these things
        # \d means any character 0-9
        # + means 1 or more of the proceeding thing
        # \Z means to check only the end of the string
        if len(re.findall('(\.\~\d+\~)\Z',thing)) == 1:
            return True
        return False

    # create list of all the archive files for this file name
    archivefiles = os.listdir(dirpath)
    archivefiles = filter(is_archive, archivefiles)
    archivefiles = filter(lambda x: x[0:x.rfind(".~")] == name, archivefiles)

    # Identify highest numbered archive file and increment by 1
    number=0
    for f in archivefiles:
        val = int(f[f.find(".~")+2:-1])
        if val > number:
            number = val
    number+=1
    
    # rename the file with the .~#~ extension
    try:
        os.rename(abspath,abspath+".~"+str(number)+"~") 
    except OSError:
        print "dl: failed to move '%s', aborting. try using sudo"%abspath
        exit(0)


def fix_backup_path(path):
    """ Adds a backslash to path and fixes tildas """
    if not path[-1] == "/":
        path+="/"
    path = expand_tildas(path)
    return path

def expand_tildas(path):
    """ Replaces ~ with the full path to the users home directory"""
    return path.replace("~",os.getenv("HOME"))

def init_backup_dir(path):
    """ Checks to see if backup directory exists, and creates one if
        it does not.
    """
    if not os.path.exists(path):
        try:
            os.makedirs(path)
        except OSError:
            # If we failed to create the directory, it's because a file with that name
            # already exists.
            print "dl: failed to create backup directory location, aborting. (hint: does name exist as a file, or re-try with better permissions?)"
            exit(0)
    elif os.path.isdir(path):
        return 
    else:
        raise RuntimeError("We should never get here")

def move_target(backup_dir_path, target_path):
    """ Moves a target file or directory to the backup directory,
        creating an archive if necessary.
    """
    # get absolute path of target
    target_path = os.path.abspath(target_path)

    # destination is full target path inside backup directory
    # also -get rid of the // that happens from combining two paths
    dest_path = (backup_dir_path+target_path).replace("//","/")

    if debugging:
        print "backup=",backup_dir_path
        print "target=",target_path
        print "dest=",dest_path
        print "target exists" if os.path.exists(dest_path) else "free target"


    if os.path.isfile(target_path) or os.path.isdir(target_path) or os.path.islink(target_path):
        # Create the directory substructure
        dest_parent_dir = os.path.dirname(dest_path)
        try:
            os.makedirs(dest_parent_dir)
        except OSError:
            if not os.path.isdir(dest_parent_dir):
                print "dl: Could not create backup directory subfolder, aborting."
                exit(0)
            elif debugging:
                print "Directory substructure already exits"

        # Create archive if path exists in backup directory
        if os.path.exists(dest_path):
            archive(dest_path)

        # move target to destination
        try:
            shutil.move(target_path,dest_path)
        except:
            print "dl: failed to remove '%s', aborting"%target_path
    else:
        print "dl: cannot remove '%s': No such file or directory"%(target_path)

def empty_trash(path):
    """ Removes stuff from the trashcan path """
    print "dl: (perminently) remove backup files [y/n]? ",
    x = raw_input()
    if x.lower() == "y" or x.lower() == "yes":
        try:
            for objname in os.listdir(path):
                if debugging:
                    print "dl: removing ",path+objname
                shutil.rmtree(path+objname)
        except:
            print "dl: failed to remove some backup files, retry with better permissions (sudo)"
    else:
        print "dl: aborting"

if __name__ == "__main__":
    # Initialize backup directory path and location
    backup_dir = os.getenv("DL_TRASH_DIR")
    if not backup_dir and os.uname()[0] == "Darwin":
        backup_dir= "~/.Trash"
    elif not backup_dir and os.uname()[0] == "Linux":
        backup_dir="~/.local/share/Trash/files"
    # If you still don't have a directory, use the default 
    elif not backup_dir:
        backup_dir = "~/.Trashcan"
        
    backup_dir = fix_backup_path(backup_dir)
    init_backup_dir(backup_dir)

    # Parse Command Line Options
    parser = argparse.ArgumentParser(description="rm, with forgivness. Removes TARGET(s) to a trash (backup) directory.")
    parser.add_argument("TARGET", type=str, help="target file", nargs="*")
    parser.add_argument("-d", "--debug", help="display debug output", action="store_true")
    parser.add_argument("--path", help="display path to backup directory", action="store_true")
    parser.add_argument("--empty-trash", help="delete all contents from the backup directory", action="store_true")
    parser.add_argument("--version", action="store_true",  help="print version information")
    args = parser.parse_args()
    if args.version:
        print __version__
        exit(0)
    if args.debug:
        debugging=True
    if args.path:
        print "dl: backup directory =",backup_dir
    elif args.empty_trash:
        empty_trash(backup_dir)
    elif args.TARGET:
        for target in args.TARGET:
            move_target(backup_dir,target)
    else:
        parser.print_help()
    
    
