#!/usr/bin/env python
# sharkattack by Tim Cheeseman
# Live Dangerously.

import argparse
import curses
import datetime
import os
import random
import sys

DEFAULT_DATA_DIR = '/var/lib/sharkattack'
DEFAULT_MODE = 'plain'
DEFAULT_TYPE = 'shark'
SHARK_DIR = 'sharks'
CAT_DIR = 'cats'
MODES = ('plain', 'color', 'curses')
TYPES = ('shark', 'cat')

def main():
    parser = argparse.ArgumentParser(description='Live dangerously.')
    parser.add_argument('--data', dest='data_dir', type=str, default=DEFAULT_DATA_DIR)
    parser.add_argument('--mode', dest='mode', type=str, choices=MODES, default=DEFAULT_MODE)
    parser.add_argument('--type', dest='type', type=str, choices=TYPES, default=DEFAULT_TYPE)

    args = parser.parse_args()

    shark_dir = os.path.join(args.data_dir, SHARK_DIR)

    # CAT HACK
    if args.type == 'cat':
        shark_dir = os.path.join(args.data_dir, CAT_DIR)

    shark_filename = random.choice([f for f in os.listdir(shark_dir) if os.path.isfile(os.path.join(shark_dir, f))])
    with open(os.path.join(shark_dir, shark_filename), 'r') as shark_file:
        shark_lines = [line.rstrip() for line in shark_file if not line.startswith("#")]

    if args.mode == 'plain':
        do_plain(shark_lines)
    elif args.mode == 'color':
        do_color(shark_lines)
    elif args.mode == 'curses':
        do_curses(shark_lines, args.type)

def do_plain(lines):
    for line in lines:
        print line

BG_BLUE       = "\033[44m"
FG_LIGHT_GRAY = "\033[37m"
RESET_COLORS  = "\033[0m"

def do_color(lines):
    max_len = max(map(len, lines))

    lines.insert(0, "")
    lines.append("")
    for line in lines:
        print "{bg}{fg} {body:<{max_len}} {}".format(RESET_COLORS,
                                                     bg=BG_BLUE,
                                                     fg=FG_LIGHT_GRAY,
                                                     body=line,
                                                     max_len=max_len)

def do_curses(lines, type):
    num_lines = len(lines)
    max_len = max(map(len, lines))

    win = curses_init()

    try:
        curses_loop(win, lines, num_lines, max_len, type)
    except (Exception, KeyboardInterrupt, SystemExit):
        # try to leave the terminal in a useable state if something goes wrong
        curses_deinit(win)
        raise

    curses_deinit(win)

def curses_init():
    win = curses.initscr()
    curses.noecho()
    curses.nocbreak()
    win.keypad(1)
    win.nodelay(1)

    curses.curs_set(0)
    if curses.has_colors():
        curses.start_color()
        curses.init_pair(1, curses.COLOR_WHITE, curses.COLOR_BLUE)
        win.bkgd(' ', curses.color_pair(1))

    return win

def curses_loop(win, lines, num_lines, max_len, type):
    draw_interval = datetime.timedelta(seconds=1)
    last_draw = datetime.datetime.now() - draw_interval
    title = "Press Q or Esc to swim to safety"

    # CAT HACK
    if type == 'cat':
        title = "Press Q or Esc to claw to safety"

    while True:
        c = win.getch()
        if c in [ord('q'), 27]:
            break

        now = datetime.datetime.now()
        if last_draw + draw_interval > now:
            continue
        last_draw = now

        (max_y, max_x) = win.getmaxyx()
        x_range = max(0, (max_x - max_len - 1) / 2)
        y_range = max(0, (max_y - num_lines - 1) / 2)
        x_offset = random.randint(-x_range, x_range)
        y_offset = random.randint(-y_range, y_range)

        win.clear()
        win.addstr(0, max_x / 2 - len(title) / 2, title)

        for i, line in enumerate(lines):
            x = max_x / 2 - max_len / 2 + x_offset
            y = max_y / 2 - num_lines / 2 + i + y_offset

            if x >= 0 and x + len(line) < max_x and y >= 0 and y < max_y:
                win.addstr(y, x, line)

        win.refresh()

def curses_deinit(win):
    win.nodelay(0)
    win.keypad(0)
    curses.cbreak()
    curses.echo()
    curses.endwin()

if __name__ == '__main__':
    main()

