#!/usr/bin/env python
#
# Warnup
# Written by Steve Gattuso <steve@stevegattuso.me>
#
# An easier way of deploying code when you can't do it
# the easy way
#
import warnup
from xtermcolor import colorize
import sys, os, subprocess, ConfigParser, datetime


def show_help():
    print("Warnup usage:")
    print("  warnup [action] [arguments]\n")
    print("Actions:")
    print("  push [file]    - Deploys file into production path")
    print("  push           - Deploys the current stage")
    print("  diff [file]    - Shows a diff between the local/production versions")
    print("  stage [file]   - Stages a file for a bulk push")
    print("  unstage [file] - Removes a file from the current stage")
    print("  stage          - Displays a list of files currently staged")

def print_error(message):
    print(colorize("[error]", 0xff0000) + " %s" % message)

def print_notice(message):
    print(colorize("[notice]", 0xffff00) + " %s" % message)

def print_success(message):
    print(colorize("[success]", 0x0DFF00) + " %s" % message)

def config_error():
    print_error("Cannot find warnup configuration file in your current working directory (.warnup)")
    sys.exit(1)

def run_diff(rel_path):
    config = warnup.get_config()
    dev_path, prod_path, temp_path = warnup.get_paths(rel_path)

    if(os.path.exists(dev_path) == False):
        print_error("File %s cannot be found on development" % rel_path)
        return

    if(os.path.exists(prod_path) == False):
        print_notice("File %s does not exist on production" % rel_path)
        return

    try:
        diff_util = config.get("utils", "diff")
    except ConfigParser.NoSectionError:
        diff_util = "diff"

    subprocess.call([diff_util, dev_path, prod_path])

def run_push(rel_path):
    dev_path, prod_path, temp_path = warnup.get_paths(rel_path)

    if(os.path.exists(dev_path) == False):
        print_error("File %s cannot be found on development" % rel_path)
        return

    backup = False
    if(os.path.exists(prod_path)):
        # Get a temporary path
        split = list(os.path.split(prod_path))
        split[-1] += ".temp"
        temp_path = os.path.join(split[0], split[1])

        print_notice("Creating backup at %s" % temp_path)
        subprocess.call(["mv", prod_path, temp_path])
        backup = True

    subprocess.call(["cp", dev_path, prod_path])
    print_success("%s successfully pushed" % rel_path)

    if(backup == False):
        return

    ans = raw_input("\nWould you like to save, delete, or restore the backup file? (s/d/r) ")
    if(ans == "d"):
        subprocess.call(["rm", temp_path])
        print_success("Backup file deleted")

    elif(ans == "r"):
        subprocess.call(["rm", prod_path])
        subprocess.call(["mv", temp_path, prod_path])
        print_success("%s has been restored to its original state" % rel_path)

    elif(ans == "s"):
        split = list(os.path.split(dev_path))
        datestr = datetime.datetime.now().strftime("%Y-%m-%d")
        split[-1] += ".%s.backup" % datestr
        save_path = os.path.join(split[0], split[1])
        subprocess.call(["mv", temp_path, save_path])
        print_success("Backup file saved to development")

def run_stage(rel_path):
    config = warnup.get_config()

    if(config == None):
        config_error()

    if(len(sys.argv) < 3):
        print_error("File not specified")
        return

    # Get the paths
    development = config.get("paths", "development")
    dev_path = os.path.join(development, rel_path)

    if(os.path.exists(dev_path) == False):
        print_error("Path does not exist")
        return
    
    warnup.stage(rel_path)
    print_success("%s successfully staged" % rel_path)

def run_unstage(rel_path):
    config = warnup.get_config()

    if(config == None):
        config_error()

    if(len(sys.argv) < 3):
        print_error("File not specified")
        return

    # Get the paths
    development = config.get("paths", "development")
    dev_path = os.path.join(development, rel_path)

    if(os.path.exists(dev_path) == False):
        print_error("Path does not exist")
        return
    
    if(warnup.unstage(rel_path) == False):
        print_error("%s is not staged" % rel_path)
        return

    print_success("%s successfully unstaged" % rel_path)

def run_show_stage():
    staged = warnup.get_staged()
    if(len(staged) == 0):
        print("Nothing staged!")
        return

    print("Staged files:")
    for path in staged:
        print("   " + colorize(path, 0xffff00))

def run_push_stage():
    staged = warnup.get_staged()

    if(len(staged) == 0):
        print_error("Nothing staged!")
        return

    run_show_stage()
    confirm = raw_input("Are you sure you would like to push these changes? (y/N)")
    if(confirm != "y"):
        print("Stage push cancelled. Exiting!");
        return

    for path in staged:
        warnup.push(path)

    print_success("Stage successfully pushed!\n")
    warnup.save_staged([])

    for path in staged:
        ans = raw_input("%s - Would you like to save, delete, or restore the backup file? (s/d/r) " % colorize(path, 0xffff00))

        if(ans == "r"):
            warnup.backup_restore(path)
        elif(ans == "d"):
            warnup.backup_delete(path)
        elif(ans == "s"):
            warnup.backup_save(path)

def main():
    if(len(sys.argv) == 1):
        show_help()
        return
    elif(sys.argv[1] == "help"):
        show_help()
        return

    # From this point on, we'll need a config file to do anything
    working_dir = os.getcwd()
    if(os.path.exists(os.path.join(working_dir, ".warnup")) is False):
        print_error("Could not find a config file (.warnup) in your current working directory. Exiting!")
    elif(sys.argv[1] == "diff"):
        if(len(sys.argv) < 3):
            print_error("File not specified")
            return
        run_diff(sys.argv[2])
    elif(sys.argv[1] == "push"):
        if(len(sys.argv) < 3):
            run_push_stage()
            return
        run_push(sys.argv[2])
    elif(sys.argv[1] == "stage"):
        if(len(sys.argv) < 3):
            run_show_stage()
            return
        run_stage(sys.argv[2])
    elif(sys.argv[1] == "unstage"):
        if(len(sys.argv) < 3):
            print_error("File not specified")
            return
        run_unstage(sys.argv[2])   
    else:
        print_error("Command not found!")
        show_help()

if __name__ == "__main__":
    main()
