# -*- coding: utf-8 -*-
from math import floor, fabs
from .mc import mc10, mantissa
from .epsilon import epsilon

__author__ = "Zasimov Alexey"
__email__ = "zasimov-a@yandex-team.ru"

_replace = [0, 1, 2, 2, 5, 5, 5, 5, 10, 10, 10]

PRECISION = 4  # Для котировок достаточно 4 знака после запятой.


def goodnumber2(x, func=float):
    """
    Для справки нужно посмотреть в GridMarks.txt
    """
    x = func(x)
    m, c = mc10(x)
    x = int(floor(m))
    x = _replace[x]
    return x * (10 ** c)


def precision_by_c(c):
    """
    Определяем достаточную точность для отображение числа с порядком c.
    Предметная область: котировки.
    Принято отображать не больше 4 знаков после запятой.
    c - это порядок ШАГА.
    """
    if c >= 1:
        return 0
    elif c > 0:
        return 1
    elif c < -4:
        return PRECISION
    else:
        return -c


def low(f, s):
    """
    Ищем хорошее число для числа f. Найденное число обязательно меньше или равно
    числу f.
    Считаем, что в числе f уже нужное число разрядов.
    """
    # Определяем порядок шага.
    _, sc = mc10(s)
    precision = precision_by_c(sc)

    # Округляем число до нужной точности.
    f = round(f, precision)
    g, c = mantissa(f, precision)

    l = g % 10
    if l == 0:
        l = 0
    elif l >= 5:
        l = 5
    elif l >= 2:
        l = 2
    else:
        l = 1
    return ((g / 10) * 10 + l) * (10 ** c)


def lh(minimum, maximum, n, minimum_step=0.0001, func=float):
    """
    Вычисление границ и шага.
    """
    minimum = func(minimum)
    maximum = func(maximum)

    # Избавляемся от возможного нуля в высоте.
    if fabs(minimum - maximum) <= epsilon:
        maximum = minimum + minimum_step
        minimum = minimum - minimum_step
        if minimum < 0:
            minimum = 0

    # Вычисляем высоту графика.
    h = maximum - minimum
    # Вычисляем шаг, при котором на графике будет n меток.
    s = h / n
    # Вычисляем красивое число для шага.
    ss = goodnumber2(s)
    ss = func(ss)
    l = low(minimum, ss)
    l = func(l)

    # Убираем слишком маленький шаг.
    if ss <= minimum_step:
        ss = minimum_step

    # Двигаем нижнюю границу ниже минимума.
    while (l - minimum) > epsilon:
        l -= ss

    # Определяем верхнюю границу.
    high = l
    while high < maximum:
        high += ss

    # Оптимизируем шаг (криво криво) и медленно медленно.
    while ((high - l) / ss) < 4:
        ss /= 2
        ss = goodnumber2(ss)

    while ((high - l) / ss) > 2 * n:
        ss *= 2
        ss = goodnumber2(ss)

    ss = max(ss, func(minimum_step))

    # Двигаем нижнюю границу так чтобы ниже нижней точки было не больше шага.
    # Здесь определяется число пустых клеток снизу.
    while ((minimum - l) / ss) > 2:
        l += ss

    high = l

    # Число клеток вверху графика.
    while ((high - maximum) / ss) < 1:
        high += ss
    while ((high - maximum) / ss) > 2:
        high -= ss
    # FIXME: 0.00001
    if (high - maximum) < 0.00001:
        high += ss

    return ss, l, high
