# -*- coding: utf-8 -*-
"""CJK wrapping and filling. Fix Python issue24665.

Copyright (C) 2015-2018, Florent Gallaire <f@gallai.re>
Copyright (C) 1999-2001, Gregory P. Ward <gward@python.net>
Copyright (C) 2002-2003, Python Software Foundation

Python2 will stay broken forever:
<https://bugs.python.org/issue24665>

Originally developed for txt2tags <http://txt2tags.org>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

__version__ = '2.2'

import textwrap
import unicodedata

import locale
locale.setlocale(locale.LC_ALL, "")

text_type = str


def is_wide(char):
    """is_wide(unicode_char) -> boolean

    Return True if unicode_char is Fullwidth or Wide, False otherwise.
    Fullwidth and Wide CJK chars are double-width.
    """
    try:
        return unicodedata.east_asian_width(char) in ('F', 'W')
    except TypeError:
        return False

def cjklen(text):
    """cjklen(object) -> integer

    Return the real width of an unicode text, the len of any other type.
    """
    if not isinstance(text, text_type):
        return len(text)
    return sum(2 if is_wide(char) else 1 for char in text)


def cjkslices(text, index):
    """cjkslices(object, integer) -> object, object

    Return the two slices of a text cut to the index.
    """
    if not isinstance(text, text_type):
        return text[:index], text[index:]
    if cjklen(text) <= index:
        return text, u''
    i = 1
    # <= and i-1 to catch the last double length char of odd line
    while cjklen(text[:i]) <= index:
        i = i + 1
    return text[:i-1], text[i-1:]

def cjkljust(text, width, char=None):
    if char is None:
        char = ' '
    txt_len = cjklen(text)
    out = text
    if width == txt_len:
        return text
    if width > txt_len:
        return out + (width - txt_len) * char
    # width < txt_len:
    return cjkslices(text, width)[0]

def cjkrjust(text, width, char=None):
    if char is None:
        char = ' '
    txt_len = cjklen(text)
    out = text
    if width == txt_len:
        return text
    if width > txt_len:
        return (width - txt_len) * char + out
    # width < txt_len:
    return cjkslices(text, width)[0]

def cjkcenter(text, width, char= ' '):
    txt_len = cjklen(text)
    out = text
    if width == txt_len:
        return text
    if width > txt_len:
        pad = int(( width - txt_len ) / 2)
        out =  pad * char + text + pad * char
        while cjklen(out) < width:
            out = char + out
        return out
    # width < txt_len:
    return cjkslices(text, width)[0]


class CJKWrapper(textwrap.TextWrapper):
    """CJK fix for the Greg Ward textwrap lib."""
    def _handle_long_word(self, reversed_chunks, cur_line, cur_len, width):
        if width < 1:
            space_left = 1
        else:
            space_left = width - cur_len
        if self.break_long_words:
            chunk_start, chunk_end = cjkslices(reversed_chunks[-1], space_left)
            cur_line.append(chunk_start)
            reversed_chunks[-1] = chunk_end
        elif not cur_line:
            cur_line.append(reversed_chunks.pop())

    def _wrap_chunks(self, chunks):
        lines = []
        if self.width <= 0:
            raise ValueError(f"invalid width {self.width!r} (must be > 0)")
        if self.width == 1 and (sum(cjklen(chunk) for chunk in chunks) >
                                sum(len(chunk) for chunk in chunks)):
            raise ValueError("invalid width 1 (must be > 1 when CJK chars)")
        chunks.reverse()
        while chunks:
            cur_line = []
            cur_len = 0

            if lines:
                indent = self.subsequent_indent
            else:
                indent = self.initial_indent
            width = self.width - len(indent)

            if self.drop_whitespace and \
                    chunks[-1].strip() == '' and \
                    lines:
                del chunks[-1]

            while chunks:
                chunk = cjklen(chunks[-1])
                if cur_len + chunk <= width:
                    cur_line.append(chunks.pop())
                    cur_len += chunk
                else:
                    break

            if chunks and cjklen(chunks[-1]) > width:
                self._handle_long_word(chunks, cur_line, cur_len, width)

            if self.drop_whitespace and \
                    cur_line and \
                    cur_line[-1].strip() == '':
                del cur_line[-1]

            if cur_line:
                lines.append(indent + ''.join(cur_line))
        return lines


# Convenience interface for CJKWrapper

def wrap(text, width=70, **kwargs):
    """Wrap a single paragraph of text, returning a list of wrapped lines.

    Reformat the single paragraph in 'text' so it fits in lines of no
    more than 'width' columns, and return a list of wrapped lines.  By
    default, tabs in 'text' are expanded with string.expandtabs(), and
    all other whitespace characters (including newline) are converted to
    space.  See CJKWrapper class for available keyword args to customize
    wrapping behaviour.
    """
    w = CJKWrapper(width=width, **kwargs)
    return w.wrap(text)


def fill(text, width=70, **kwargs):
    """Fill a single paragraph of text, returning a new string.

    Reformat the single paragraph in 'text' to fit in lines of no more
    than 'width' columns, and return a new string containing the entire
    wrapped paragraph.  As with wrap(), tabs are expanded and other
    whitespace characters converted to space.  See CJKWrapper class for
    available keyword args to customize wrapping behaviour.
    """
    w = CJKWrapper(width=width, **kwargs)
    return w.fill(text)

if __name__ == '__main__':
    a='这显然不是巧合。美国敌视中国之情绪正在加深、加剧'
    print(cjklen(a) * '-')
    print(f'{a}')
    print('len =', len(a))
    print('cjklen =', cjklen(a))

    print('\nCentering at 78')
    print((cjklen(a) * '-' ).center(78, '*'))
    print(cjkcenter(a, 78, '*'))

    print('\nCentering at 40')
    print(40 * '-')
    print(cjkcenter(a, 40, '*'))


    print('\n', cjkslices(a, cjklen(a)-4)[0])
