"""Ví dụ BTVN: nhị phân, Euclid và tổng kết tệp giả định.

Chạy với Python 3, từ thư mục chứa mã và dữ liệu tải về:
  python3 g11-cs-thuc-hanh-de-quy.py nhi-phan 10101
  python3 g11-cs-thuc-hanh-de-quy.py ucln 84 30
  python3 g11-cs-thuc-hanh-de-quy.py chieu-cao chieucao.inp ketqua.out
Các hàm đệ quy dùng dữ liệu nhỏ; không thay đổi giới hạn đệ quy Python.
"""
import argparse
import math
from pathlib import Path


def dec(s, n):
    # s không rỗng, chỉ gồm 0/1; 1 <= n <= len(s).
    if n == 1:
        return int(s[0])
    return 2 * dec(s, n - 1) + int(s[n - 1])


def dec_list(A, n):
    # A chứa các số nguyên 0/1; 0 <= n <= len(A).
    if n == 0:
        return 0
    return 2 * dec_list(A, n - 1) + A[n - 1]


def gcd(a, b):
    # a, b nguyên không âm, không đồng thời bằng 0.
    if b == 0:
        return a
    return gcd(b, a % b)


def gcd_lap(a, b):
    while b != 0:
        r = a % b
        a = b
        b = r
    return a


def gcd_tru(a, b):
    # Bản trừ liên tiếp này chỉ nhận hai số nguyên dương.
    if a == b:
        return a
    if a > b:
        return gcd_tru(a - b, b)
    return gcd_tru(a, b - a)


def minmax(A, k):
    # A không rỗng; 0 <= k < len(A).
    if k == 0:
        return A[0], A[0]
    low, high = minmax(A, k - 1)
    return min(low, A[k]), max(high, A[k])


def doc_chieu_cao(fi):
    DS, CC = [], []
    with open(fi, encoding='utf-8') as f:
        for line in f:
            parts = line.split()
            if not parts:
                continue
            if len(parts) < 2:
                raise ValueError('Mỗi dòng cần tên mẫu và chiều cao.')
            ten = ' '.join(parts[:-1])
            h = float(parts[-1])
            if not math.isfinite(h) or h <= 0:
                raise ValueError('Chiều cao phải là số dương hữu hạn.')
            DS.append(ten)
            CC.append(h)
    if not CC:
        raise ValueError('Tệp chưa có bản ghi để tìm min/max.')
    return DS, CC


def ghi_ket_qua(fo, DS, CC):
    low, high = minmax(CC, len(CC) - 1)
    imin = CC.index(low)
    imax = CC.index(high)
    with open(fo, 'w', encoding='utf-8') as f:
        print(DS[imin], f'{CC[imin]:.2f}', file=f)
        print(DS[imax], f'{CC[imax]:.2f}', file=f)
    return imin, imax


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    modes = parser.add_subparsers(dest='mode', required=True)
    binary = modes.add_parser('nhi-phan')
    binary.add_argument('s')
    divisor = modes.add_parser('ucln')
    divisor.add_argument('a', type=int)
    divisor.add_argument('b', type=int)
    height = modes.add_parser('chieu-cao')
    height.add_argument('fi', type=Path)
    height.add_argument('fo', type=Path)
    args = parser.parse_args()
    try:
        if args.mode == 'nhi-phan':
            if not args.s or any(c not in '01' for c in args.s):
                raise ValueError('Cần một xâu không rỗng chỉ gồm 0 và 1.')
            print(dec(args.s, len(args.s)))
        elif args.mode == 'ucln':
            if args.a < 0 or args.b < 0 or (args.a == 0 and args.b == 0):
                raise ValueError('Cần hai số không âm, không đồng thời bằng 0.')
            print(gcd(args.a, args.b))
        else:
            if args.fi.resolve() == args.fo.resolve():
                raise ValueError('Tệp kết quả phải khác tệp đầu vào.')
            DS, CC = doc_chieu_cao(args.fi)
            ghi_ket_qua(args.fo, DS, CC)
            print('Đã ghi:', args.fo)
    except (ValueError, OSError) as error:
        parser.exit(2, f'Dữ liệu hoặc tệp không phù hợp: {error}\n')
    except RecursionError:
        parser.exit(2, 'Dữ liệu quá lớn cho mẫu đệ quy trực tiếp; dùng bộ thử nhỏ.\n')


if __name__ == '__main__':
    main()
