from urllib.request import urlopen


def genurl(curfrom, curto, amount):
    """
    Returns: A URL which can be used to access Cornell's exchange
    service.This module generates the URL required by the Corenll
    server's currency exchange program, with the required infomation
    given by the user.

    Parameter curfrom:the currency on hand
    Precondition: curfrom is a string

    Parameter curto:the currency to convert to
    Precondition: curfrom is a string

    Parameter amount: amount of currency to convert
    Precondition: amount is a string"""

    p1 = "http://cs1110.cs.cornell.edu/2018fa/a1server.php?from="
    p2 = "&to="
    p3 = "&amt="
    gurl = (p1 + curfrom + p2 + curto + p3 + amount)
    return gurl


def getrate(url):
    """
    Returns: The information about the change, in the type of string
    This module gets the currency exchange infomation from the Cornell
    server,and returns in the form of a string. The response should be
    a string of the form
    '{"from":"<old-amt>","to":"<new-amt>","success":true, "error":""}'.
    The input of the module is the URL required by the Cornell server,
    which shall be generated by the module 'genurl()'.

    Parameter url:the URL of the convert service
    Precondition: url is a string"""

    doc = urlopen(url)
    docstr = doc.read()
    doc.close()
    jstr = docstr.decode('UTF-8')
    return jstr


def strproc(inf):
    """
    Returns: amount of currency received in the given exchange,in the
    type of string.This module breaks up the string, which is gotten
    by the function'geturl()', to separate the target currency amount
    from the string, and return the target currency amount in the type
    of string.

    Parameter inf: the string needs to be processed
    Precondition: inf is a string"""

    i = 0
    count1 = 0
    count2 = 0
    while i < len(inf):
        if i > 0:
            if inf[i].isnumeric():
                if not (inf[i-1].isnumeric() or (inf[i-1] in ".E-")):
                    count1 = count1 + 1
                    if count1 == 2:
                        signstart = i
            if inf[i] == " " and inf[i-1].isnumeric():
                    count2 = count2 + 1
                    if count2 == 2:
                        signstop = i
        i = i+1
    target = inf[int(signstart):int(signstop)]
    return target


def exchange(currency_from, currency_to, amount_from):
    """
    Returns: amount of currency received in the given exchange.
    In this exchange, the user is changing amount_from money in currency
    currency_from to the currency currency_to. The value returned
    represents the amount in currency currency_to.

    The value returned has type float.

    Parameter currency_from: the currency on hand
    Precondition: currency_from is a string for a valid currency code

    Parameter currency_to: the currency to convert to
    Precondition: currency_to is a string for a valid currency code

    Parameter amount_from: amount of currency to convert
    Precondition: amount_from is a float"""

    url_run = genurl(str(currency_from), str(currency_to), str(amount_from))
    str_run = getrate(url_run)
    amount_to = float(strproc(str_run))
    return amount_to


def main():
    curfrom = input("Currency from? -")
    curto = input("Currency to? -")
    amount = float(input("Amount of the source currency? -"))
    i = exchange(curfrom, curto, amount)
    print("The amount of the destination currency is %s" % i)


# The following test functions are not used in the final main program.
t = "http://cs1110.cs.cornell.edu/2018fa/a1server.php?from=USD&to=EUR&amt=2.5"
# To consist with PEP-8, the too-long sample string has been divided
k1 = '{ "src" : "2.5 United States Dollars", "dst"'
k2 = ' : "2.2160175 Euros", "valid" : true, "error" : "" }'
k = k1 + k2


def test_genurl():
    """
    This function tests the 'genurl()' module. The input
    (curfrom,curto,amount)
    is given and the output is compared with the expected result."""

    expcurl = t
    assert(genurl("USD", "EUR", "2.5") == expcurl)
    print("test_genurl successfully conducted")


def test_getrate():
    """
    This function tests the 'getrate()' module. The input URL is manually
    given and the output is compared with the result fetched manually by
    the browser."""
    testurl = t
    assert(getrate(testurl) == k)
    print("test_getrate successfully conducted")


def test_strproc():
    """
    This fuction tests  the 'strproc' module. A standard input string is
    given to test the functionbility of the module. """

    teststr = k
    assert(strproc(teststr) == "2.2160175")
    print("test_strproc successfully conducted")


def test_exchange():
    """
    This tests the final function of exchange."""
    assert(exchange('USD', 'EUR', 2.5) == 2.2160175)
    assert(exchange('USD', 'CNY', 1.0) == 6.880846)
    assert(exchange('CNY', 'JPY', 1.0) == 15.683391257412)
    print("test_exchange successfully conducted")


def testall():
    """
    Test all the functions."""
    test_genurl()
    test_getrate()
    test_strproc()
    test_exchange()
    print("All tests have been successfully conducted")


if __name__ == '__main__':
    main()
