# -*- coding: utf-8 -*-
# Copyright 1999-2025 Alibaba Group Holding Ltd.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import itertools
import logging.config
import os
import platform
import sys
import warnings

try:
    if sys.version_info[:2] < (3, 3):
        import xml.etree.cElementTree as ElementTree
    else:
        import xml.etree.ElementTree as ElementTree
except ImportError:
    import xml.etree.ElementTree as ElementTree
try:
    ElementTreeParseError = getattr(ElementTree, "ParseError")
except AttributeError:
    ElementTreeParseError = getattr(ElementTree, "XMLParserError")
try:
    from collections.abc import Iterable
except ImportError:
    from collections import Iterable

from unicodedata import east_asian_width

from .lib import six

PY27 = six.PY2 and sys.version_info[1] == 7
LESS_PY32 = sys.version_info[:2] < (3, 2)
LESS_PY33 = sys.version_info[:2] < (3, 3)
LESS_PY34 = sys.version_info[:2] < (3, 4)
LESS_PY35 = sys.version_info[:2] < (3, 5)
LESS_PY36 = sys.version_info[:2] < (3, 6)
PYPY = platform.python_implementation().lower() == "pypy"

SEEK_SET = 0
SEEK_CUR = 1
SEEK_END = 2

# Definition of East Asian Width
# http://unicode.org/reports/tr11/
# Ambiguous width can be changed by option
_EAW_MAP = {"Na": 1, "N": 1, "W": 2, "F": 2, "H": 1}

import decimal

DECIMAL_TYPES = [
    decimal.Decimal,
]

import json  # don't remove

try:
    TimeoutError = TimeoutError
except NameError:
    TimeoutError = type("TimeoutError", (RuntimeError,), {})


if six.PY3:
    lrange = lambda *x: list(range(*x))
    lzip = lambda *x: list(zip(*x))
    lkeys = lambda x: list(x.keys())
    lvalues = lambda x: list(x.values())
    litems = lambda x: list(x.items())

    irange = range
    izip = zip

    long_type = int

    import io

    StringIO = io.StringIO
    BytesIO = io.BytesIO

    if LESS_PY36:
        from .lib import enum
    else:
        import enum

    if LESS_PY33:
        try:
            import cdecimal as decimal

            DECIMAL_TYPES.append(decimal.Decimal)
        except:
            import decimal
    else:
        import decimal

    def u(s):
        return s

    def strlen(data, encoding=None):
        # encoding is for compat with PY2
        return len(data)

    def east_asian_len(data, encoding=None, ambiguous_width=1):
        """
        Calculate display width considering unicode East Asian Width
        """
        if isinstance(data, six.text_type):
            return sum(
                [_EAW_MAP.get(east_asian_width(c), ambiguous_width) for c in data]
            )
        else:
            return len(data)

    dictconfig = lambda config: logging.config.dictConfig(config)

    import builtins
    from concurrent import futures  # don't remove

    from .lib import cgi_compat as cgi

    UnsupportedOperation = io.UnsupportedOperation

    try:
        from .lib.version import Version
    except BaseException:
        from distutils.version import LooseVersion as Version

    from threading import Semaphore
else:
    lrange = range
    lzip = zip
    lkeys = lambda x: x.keys()
    lvalues = lambda x: x.values()
    litems = lambda x: x.items()

    irange = xrange
    izip = itertools.izip

    long_type = long

    from .lib import enum

    try:
        import cdecimal as decimal

        DECIMAL_TYPES.append(decimal.Decimal)
    except ImportError:
        import decimal

    try:
        import cStringIO as StringIO
    except ImportError:
        import StringIO
    StringIO = BytesIO = StringIO.StringIO

    def u(s):
        return unicode(s, "unicode_escape")

    def strlen(data, encoding=None):
        try:
            data = data.decode(encoding)
        except UnicodeError:
            pass
        return len(data)

    def east_asian_len(data, encoding=None, ambiguous_width=1):
        """
        Calculate display width considering unicode East Asian Width
        """
        if isinstance(data, six.text_type):
            try:
                data = data.decode(encoding)
            except UnicodeError:
                pass
            return sum(
                [_EAW_MAP.get(east_asian_width(c), ambiguous_width) for c in data]
            )
        else:
            return len(data)

    dictconfig = lambda config: logging.config.dictConfig(config)

    import cgi

    import __builtin__ as builtins  # don't remove

    from .lib import futures  # don't remove

    UnsupportedOperation = type("UnsupportedOperation", (OSError, ValueError), {})

    from distutils.version import LooseVersion as Version
    from threading import _Semaphore as _PySemaphore

    from .lib.monotonic import monotonic

    class Semaphore(_PySemaphore):
        def acquire(self, blocking=True, timeout=None):
            if not blocking and timeout is not None:
                raise ValueError("can't specify timeout for non-blocking acquire")
            rc = False
            endtime = None
            with self.__cond:
                while self.__value == 0:
                    if not blocking:
                        break
                    if timeout is not None:
                        if endtime is None:
                            endtime = monotonic() + timeout
                        else:
                            timeout = endtime - monotonic()
                            if timeout <= 0:
                                break
                    self.__cond.wait(timeout)
                else:
                    self.__value -= 1
                    rc = True
            return rc


if LESS_PY32:
    try:
        from .tests.dictconfig import dictConfig

        dictconfig = lambda config: dictConfig(config)
    except ImportError:
        pass

if six.PY3:
    from contextlib import suppress
else:
    from contextlib import contextmanager

    @contextmanager
    def suppress(*exceptions):
        try:
            yield
        except exceptions:
            pass


Enum = enum.Enum
DECIMAL_TYPES = tuple(DECIMAL_TYPES)
Decimal = decimal.Decimal

try:
    import pandas as pd

    if not hasattr(pd.DataFrame, "sort_values"):
        pd.DataFrame.sort_values = pd.DataFrame.sort

    from pandas.core.internals import blocks as pd_blocks

    if not hasattr(pd_blocks, "new_block"):
        pd_blocks.new_block = pd_blocks.make_block

    if not hasattr(pd.RangeIndex, "start"):
        pd.RangeIndex.start = property(fget=lambda x: x._start)
        pd.RangeIndex.stop = property(fget=lambda x: x._stop)
        pd.RangeIndex.step = property(fget=lambda x: x._step)
except (ImportError, ValueError) as ex:
    if not isinstance(ex, ImportError):
        warnings.warn("Import of pandas skipped. Reasons: %s" % str(ex))

try:
    import numpy as np

    if not hasattr(np, "float_"):
        np.float_ = np.float64
    if not hasattr(np, "int_"):
        np.int_ = np.int64
except ImportError:
    pass

if sys.version_info[0] > 2:
    # workaround for polluted sys.path due to some packages
    try:
        import http.client
    except ImportError:
        sys.modules.pop("http", None)
        old_path = list(sys.path)
        sys.path = [os.path.dirname(os.__file__)] + sys.path
        import http.client

        sys.path = old_path

import datetime

from .lib.ext_types import Monthdelta
from .lib.lib_utils import dir2, getargspec, getfullargspec, isvalidattr
from .lib.six.moves import configparser as ConfigParser
from .lib.six.moves import cPickle as pickle
from .lib.six.moves import reduce, reload_module
from .lib.six.moves.queue import Empty, Queue
from .lib.six.moves.urllib.parse import (
    parse_qsl,
    quote,
    quote_plus,
    unquote,
    urlencode,
    urlparse,
)
from .lib.six.moves.urllib.request import urlretrieve


class _FixedOffset(datetime.tzinfo):
    """
    A class building tzinfo objects for fixed-offset time zones.
    Note that FixedOffset(0, "UTC") is a different way to build a
    UTC tzinfo object.
    """

    def __init__(self, offset, name=None):
        self.__offset = datetime.timedelta(minutes=offset)
        self.__name = name

    def utcoffset(self, dt):
        return self.__offset

    def tzname(self, dt):
        return self.__name

    def dst(self, dt):
        return _ZERO_TIMEDELTA


try:
    import zoneinfo

    utc = zoneinfo.ZoneInfo("UTC")
    FixedOffset = _FixedOffset
except ImportError:
    try:
        import pytz

        utc = pytz.utc
        FixedOffset = pytz._FixedOffset
    except ImportError:
        _ZERO_TIMEDELTA = datetime.timedelta(0)
        FixedOffset = _FixedOffset
        utc = FixedOffset(0, "UTC")


try:
    from email.utils import parsedate_to_datetime
except ImportError:
    import datetime
    from email.utils import parsedate_tz

    def parsedate_to_datetime(data):
        dt_tuple_with_tz = parsedate_tz(data)
        dtuple = dt_tuple_with_tz[:-1]
        tz = dt_tuple_with_tz[-1]
        if tz is None:
            return datetime.datetime(*dtuple[:6])
        return datetime.datetime(*dtuple[:6], tzinfo=FixedOffset(tz / 60.0))


if not hasattr(datetime, "UTC"):
    datetime_utcnow = datetime.datetime.utcnow
else:

    def datetime_utcnow():
        return datetime.datetime.now(datetime.UTC).replace(tzinfo=None)


__all__ = [
    "DECIMAL_TYPES",
    "ConfigParser",
    "Decimal",
    "ElementTree",
    "ElementTreeParseError",
    "Empty",
    "Enum",
    "FixedOffset",
    "Iterable",
    "Monthdelta",
    "Queue",
    "Semaphore",
    "TimeoutError",
    "Version",
    "builtins",
    "cgi",
    "datetime_utcnow",
    "decimal",
    "dictconfig",
    "logging.config",
    "parse_qsl",
    "parsedate_to_datetime",
    "pickle",
    "quote",
    "quote_plus",
    "reduce",
    "reload_module",
    "suppress",
    "sys",
    "unquote",
    "urlencode",
    "urlparse",
    "urlretrieve",
    "utc",
]
