#!/usr/bin/env python
#

"""
gupload: graphterm-aware upload

To upload file:
   gupload directory/filename

To pipe uploaded data:
   gupload | cat > outfile

To switch stdout and stderr:
   gupload 3>&1 1>&2 2>&3-
"""

import base64
import json
import os
import sys
import tty
import termios

from optparse import OptionParser

import gterm

CHUNK_BYTES = 4096

Work_dir = os.getenv("PWD", "") or os.getcwd()

usage = "usage: %prog [-f] [<filepath/directory>]"
parser = OptionParser(usage=usage)
parser.add_option("-w", "--write",
                  action="store_true", dest="write", default=False,
                  help="Overwrite existing file")
parser.add_option("-o", "--stdout",
                  action="store_true", dest="stdout", default=False,
                  help="Use STDOUT for pagelet output")
parser.add_option("-l", "--loop",
                  action="store_true", dest="loop", default=False,
                  help="Loop (multiple) uploads")
parser.add_option("-q", "--quiet",
                  action="store_true", dest="quiet", default=False,
                  help="Quiet")
parser.add_option("", "--verbose",
                  action="store_true", dest="verbose", default=False,
                  help="Verbose")

(options, args) = parser.parse_args()

if len(args) > 1:
    print >> sys.stderr, "To many arguments"
    sys.exit(1)

assert sys.stdin.isatty()

to_dir = False
if args:
    expname = os.path.expanduser(args[0])
    filepath = os.path.normcase(os.path.normpath(os.path.join(Work_dir, expname)))
elif sys.stdout.isatty():
    filepath = "."
else:
    filepath = ""

if filepath:
    if os.path.exists(filepath):
        if os.path.isdir(filepath):
            to_dir = True
        elif not options.write:
            print >> sys.stderr, "Specify -w option to overwrite file %s" % filepath
            sys.exit(1)
    else:
        head, tail = os.path.split(filepath)
        if head:
            if os.path.exists(head):
                if not os.path.isdir(head):
                    print >> sys.stderr, "Cannot overwrite file %s" % head
                    sys.exit(1)
            else:
                print >> sys.stderr, "Please create directory %s" % head
                sys.exit(1)

if options.loop and not to_dir:
    sys.exit("Error: loop option inconsistent with non-directory destination")

while True:
    if not options.quiet and not options.stdout:
        print >> sys.stderr, "Uploading file..."

    params = {"display": "block", "current_directory": Work_dir}
    html_headers = {"x_gterm_response": "upload_file",
                    "x_gterm_parameters": params
                    }
    gterm.wrap_write("", headers=html_headers, stderr=not options.stdout)

    Stdin_fd = sys.stdin.fileno()
    Saved_settings = termios.tcgetattr(Stdin_fd)
    Stdout_data = None

    try:
        # Raw tty input without echo
        tty.setraw(Stdin_fd)
        line = ""
        header_line = ""
        while True:
            ch = sys.stdin.read(1)
            if ch == "\x03" or ch == "\x04": # ^C/^D
                gterm.write_blank(stderr=not options.stdout)
                sys.exit(1)
            if ch != "\n":
                line += ch
                continue
            if line:
                header_line = line
                line = ""
            else:
                # Terminal null line
                break

        if options.verbose:
            print >> sys.stderr, "header=%s\n" % (header_line,)

        # Process headers
        if not header_line:
            gterm.write_blank(stderr=not options.stdout)
            sys.exit(1)

        headers = json.loads(header_line)

        if "x_gterm_filepath" not in headers:
            gterm.write_blank(stderr=not options.stdout)
            sys.exit(1)

        content_type = headers["content_type"]
        if content_type.startswith("none/"):
            gterm.write_blank(stderr=not options.stdout)
            sys.exit(1)

        filename = headers["x_gterm_filepath"]
        expect_length = headers["x_gterm_length"]
        if options.verbose:
            print >> sys.stderr, "file=%s, type=%s, expect_len=%s\n" % (filename, content_type, expect_length)

        if expect_length:
            count = expect_length
            assert not (count % 4)
            prefix = ""
            content_list = []
            while count > 0:
                chunk = sys.stdin.read(min(count, CHUNK_BYTES))
                assert chunk
                count = count - len(chunk)
                line = prefix + chunk
                prefix = ""
                offset = len(line) % 4
                if offset:
                    prefix = line[-offset:]
                    line = line[:-offset]
                if options.verbose:
                    print >> sys.stderr, "line(%d,%s)=%s" % (len(chunk), count, line,)
                content_list.append(base64.b64decode(line))
            assert not prefix
            content = "".join(content_list)
        else:
            b64_content = ""
            content = ""
    except KeyboardInterrupt:
        sys.exit(1)
    finally:
        termios.tcsetattr(Stdin_fd, termios.TCSADRAIN, Saved_settings)

    gterm.write_blank(stderr=not options.stdout)

    if filepath:
        if to_dir:
            tempath = os.path.join(filepath, filename)
        else:
            tempath = filepath
        with open(tempath, "w") as f:
            f.write(content)
        if not options.quiet:
            print >> sys.stderr, "Uploaded file "+tempath

        if not options.loop:
            break
    else:
        Stdout_data = content
        break

if Stdout_data is not None:
    if options.stdout:
        sys.stderr.write(content)
    else:
        sys.stdout.write(content)
