# The contents of this file are subject to the BitTorrent Open Source License
# Version 1.0 (the License).  You may not copy or use this file, in either
# source code or executable form, except in compliance with the License.  You
# may obtain a copy of the License at http://www.bittorrent.com/license/.
#
# Software distributed under the License is distributed on an AS IS basis,
# WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
# for the specific language governing rights and limitations under the
# License.

# Written by Bill Bumgarner and Bram Cohen

import os
import re
import urllib
from types import *
from cStringIO import StringIO

from BitTorrent.obsoletepythonsupport import *

from BitTorrent.defaultargs import MyBool, MYTRUE
from BitTorrent import BTFailure, is_frozen_exe
from BitTorrent.bencode import bdecode

def makeHelp(uiname, defaults):
    ret = ''
    ret += (_("Usage: %s ") % uiname)
    if uiname.startswith('btlaunchmany'):
        ret += _("[OPTIONS] [TORRENTDIRECTORY]\n\n")
        ret += _("If a non-option argument is present it's taken as the value\n"
                 "of the torrent_dir option.\n")
    elif uiname == 'btdownloadgui':
        ret += _("[OPTIONS] [TORRENTFILES]\n")
    elif uiname.startswith('btdownload'):
        ret += _("[OPTIONS] [TORRENTFILE]\n")
    elif uiname == 'btmaketorrent':
        ret += _("[OPTION] TRACKER_URL FILE [FILE]\n")
    ret += '\n'
    ret += _("arguments are -\n") + formatDefinitions(defaults, 80)
    return ret

def printHelp(uiname, defaults):
    if uiname[-3:] == 'gui' and is_frozen_exe:
        from BitTorrent.GUI import HelpWindow
        HelpWindow(None, makeHelp(uiname, defaults))
    else:
        print makeHelp(uiname, defaults)

def formatDefinitions(options, COLS):
    s = StringIO()
    indent = " " * 10
    width = COLS - 11

    if width < 15:
        width = COLS - 2
        indent = " "

    for option in options:
        (longname, default, doc) = option
        if doc == '':
            continue
        s.write('--' + longname)
        is_boolean = type(default) is MyBool
        if is_boolean:
            s.write(', --no_' + longname)
        else:
            s.write(' <arg>')
        s.write('\n')
        if default is not None:
            doc += _(" (defaults to ") + repr(default) + ')'
        i = 0
        for word in doc.split():
            if i == 0:
                s.write(indent + word)
                i = len(word)
            elif i + len(word) >= width:
                s.write('\n' + indent + word)
                i = len(word)
            else:
                s.write(' ' + word)
                i += len(word) + 1
        s.write('\n\n')
    return s.getvalue()

def usage(str):
    raise BTFailure(str)

def format_key(key):
    if len(key) == 1:
        return '-%s'%key
    else:
        return '--%s'%key

urlpat = re.compile('^\w+://')

def open_arg(arg):
    filename = arg
    ret_data = None
    errors = []
    if os.access(filename, os.F_OK):
        f = None
        try:
            f = file(filename, 'rb')
            data = f.read()
            f.close()
        except Exception, e:
            if f is not None:
                f.close()
            if _("Temporary Internet Files") in filename:
                errors.append(_("Could not read %s: %s. You are probably "
                                "using a broken Internet Explorer version "
                                "that passed BitTorrent a filename that "
                                "doesn't exist. To work around the problem, "
                                "try clearing your Temporary Internet Files "
                                "or right-click the link and save the "
                                ".torrent file to disk first.") %
                                (filename, str(e)))
            else:
                errors.append((_("Could not read %s") % filename) + (': %s' % str(e)))

        else:
            ret_data = data
    elif urlpat.match(filename):
        err_str = _("Could not download or open \n%s\n"
                    "Try using a web browser to download the torrent file." %
                    filename)
        try:
            u = urllib.urlopen(filename)
            data = u.read()
            u.close()
            b = bdecode(data)
        except Exception, e:
            u.close()
            errors.append(err_str + "\n(%s)" % e)
        else:
            u.close()
            ret_data = data
    else:
        errors.append(_("Could not read %s") % filename)
    return ret_data, errors

def parseargs(argv, options, minargs=None, maxargs=None, presets=None):
    config = {}
    for option in options:
        longname, default, doc = option
        config[longname] = default
    args = []
    pos = 0
    if presets is None:
        presets = {}
    else:
        presets = presets.copy()
    while pos < len(argv):
        if argv[pos][:1] != '-':             # not a cmdline option
            args.append(argv[pos])
            pos += 1
        else:
            key, value = None, None
            if argv[pos].startswith('--'):        # --aaa 1
                if argv[pos].startswith('--no_'):
                    key = argv[pos][5:]
                    boolval = False
                else:
                    key = argv[pos][2:]
                    boolval = True
                if key not in config:
                    raise BTFailure(_("unknown key ") + format_key(key))
                if type(config[key]) is MyBool: # boolean cmd line switch, no value
                    value = boolval
                    pos += 1
                else: # --argument value
                    if pos == len(argv) - 1:
                        usage(_("parameter passed in at end with no value"))
                    key, value = argv[pos][2:], argv[pos+1]
                    pos += 2
            elif argv[pos][:1] == '-':
                key = argv[pos][1:2]
                if len(argv[pos]) > 2:       # -a1
                    value = argv[pos][2:]
                    pos += 1
                else:                        # -a 1
                    if pos == len(argv) - 1:
                        usage(_("parameter passed in at end with no value"))
                    value = argv[pos+1]
                    pos += 2
            else:
                raise BTFailure(_("command line parsing failed at ")+argv[pos])

            presets[key] = value
    parse_options(config, presets)
    config.update(presets)
    for key, value in config.items():
        if value is None:
            usage(_("Option %s is required.") % format_key(key))
    if minargs is not None and len(args) < minargs:
        usage(_("Must supply at least %d args.") % minargs)
    if maxargs is not None and len(args) > maxargs:
        usage(_("Too many args - %d max.") % maxargs)
    return (config, args)

def parse_options(defaults, newvalues):
    for key, value in newvalues.iteritems():
        if not defaults.has_key(key):
            raise BTFailure(_("unknown key ") + format_key(key))
        try:
            t = type(defaults[key])
            if t is MyBool:
                if value in ('True', '1', MYTRUE, True):
                    value = True
                else:
                    value = False
                newvalues[key] = value
            elif t in (StringType, NoneType):
                newvalues[key] = value
            elif t in (IntType, LongType):
                if value == 'False':
                    newvalues[key] == 0
                elif value == 'True':
                    newvalues[key] == 1
                else:
                    newvalues[key] = int(value)
            elif t is FloatType:
                newvalues[key] = float(value)
            else:
                raise TypeError, str(t)

        except ValueError, e:
            raise BTFailure(_("wrong format of %s - %s") % (format_key(key), str(e)))

