# coding: utf-8
from ru.curs.celesta import CelestaException


def generateSortValue(number, rankList=[3]):
    u'''Функция формирует сортировочное значение из номера иерархии Дьюи.
    @number - номер иерархии Дьюи типа 1.1.1
    @rankList - список отвечающий за количество разрядов на каждом уровне rankList[0] количество по умолчанию
    Данный параметр не обязателен по умолчанию равен [3]
    Пример: generateSortValue('1.2.3.4', [3,1,2,3])='102003004' '''
    if not(isinstance(number, (str, unicode)) and isinstance(rankList, list)):
        raise CelestaException(u'Неверный формат аргументов. аргументы должны иметь вид (строка,список)')
    lenRankList = len(rankList)
#     убираем пустые строки
    numberList = filter(bool, number.split('.'))

    sortVal = []
    for idx, val in enumerate(numberList):
        rank = rankList[idx + 1] if idx + 1 < lenRankList else rankList[0]
        sortVal.append(val.zfill(rank))
    return ''.join(sortVal)


def moveNodeInHierarchy(context, cursorInstance, numberField, position, isOneHierarchy=False):
    u'''Функция передвигает куст в иерархии на указанную позицию на том же уровне
    cursorInstance - курсор, соджержащий корень передвигаемого узла.
    При этом уникальность нумерации не отслеживается.'''
    currentNumber = getattr(cursorInstance, numberField)
    numberList = currentNumber.split('.')
    level = len(numberList)
    # Создаем клон основного курсора и копируем в него фильтры
    cursorInstanceClone = cursorInstance.__class__(context)
    if not isOneHierarchy:
        cursorInstanceClone.copyFiltersFrom(cursorInstance)
    cursorInstanceClone.setFilter(numberField, '''('%s.'%%)''' % currentNumber)
    cursorInstanceClone.limit(0, 0)
    # Меняем номер всех узлов куста, кроме корня
    for cursorInstanceClone in cursorInstanceClone.iterate():
        numberListChild = getattr(cursorInstanceClone, numberField).split('.')
        numberListChild[level - 1] = unicode(position)
        cursorInstanceClone.__setattr__(numberField, '.'.join(numberListChild))
        cursorInstanceClone.update()
    # Меняем номер корня
    numberList[-1] = unicode(position)
    cursorInstance.__setattr__(numberField, '.'.join(numberList))
    cursorInstance.update()
    cursorInstanceClone.close()


def deleteNodeFromHierarchy(context, cursorInstance, numberField, sortField, isOneHierarchy=False):
    u'''Функция удаляет куст из иерархии, сдвигая все нижестоящие кусты на одну позицию вверх'''
    currentNumber = getattr(cursorInstance, numberField)
    numberList = currentNumber.split('.')
    # Создаем клон основного курсора и копируем в него фильтры
    cursorInstanceClone = cursorInstance.__class__(context)
    if not isOneHierarchy:
        cursorInstanceClone.copyFiltersFrom(cursorInstance)
    cursorInstanceClone.limit(0, 0)
    cursorInstanceClone.orderBy(sortField)
    # Удаляем все узлы куста кроме корня
    cursorInstanceClone.setFilter(numberField, '''('%s.'%%)''' % currentNumber)
    for cursorInstanceClone in cursorInstanceClone.iterate():
        cursorInstanceClone.delete()
    # Удаляем корень куста
    currentSort = getattr(cursorInstance, sortField)
    cursorInstance.delete()
    # Сдвигаем все нижестоящие кусты на одну позицию вверх
    if '.' in currentNumber:
        sqlPattern = '''('%s.'%%)&!('%s.'%%'.'%%)''' % ('.'.join(numberList[:-1]), '.'.join(numberList[:-1]))
    else:
        sqlPattern = '''(!%'.'%)'''

    cursorInstanceClone.setFilter(numberField, sqlPattern)
    cursorInstanceClone.setFilter(sortField, '''>'%s' ''' % currentSort)
    cursorInstanceClone.orderBy(sortField)
    for cursorInstanceClone in cursorInstanceClone.iterate():
        numberListChild = getattr(cursorInstanceClone, numberField).split('.')
        moveNodeInHierarchy(context, cursorInstanceClone, numberField, int(numberListChild[-1]) - 1)
    cursorInstanceClone.close()


def changeNodePositionInLevelOfHierarchy(context, cursorInstance, numberField,
                                         sortField, shift, isOneHierarchy=False):
    u'''Функция перемещает куст на @shift позиций, сдвигая при этом необходимое количество соседних кустов'''
    currentNumber = getattr(cursorInstance, numberField)
    numberList = currentNumber.split('.')
    # Создаем клон основного курсора и копируем в него фильтры
    cursorInstanceClone = cursorInstance.__class__(context)
    if not isOneHierarchy:
        cursorInstanceClone.copyFiltersFrom(cursorInstance)
    cursorInstanceClone.limit(0, 0)
    currentSort = getattr(cursorInstance, sortField)
    # Перемещаем указанный куст на нулевую позицию
    moveNodeInHierarchy(context, cursorInstance, numberField, 0)
    # Перемещаем необходимое количество соседних кустов
    if '.' in currentNumber:
        sqlPattern = '''('%s.'%%)&(!'%s.'%%'.'%%)''' % ('.'.join(numberList[:-1]), '.'.join(numberList[:-1]))
    else:
        sqlPattern = '''(!%'.'%)'''

    cursorInstanceClone.setFilter(numberField, sqlPattern)
    if shift >= 0:
        sign = 1
        cursorInstanceClone.setFilter(sortField, '''>'%s' ''' % currentSort)
        cursorInstanceClone.orderBy(sortField)
    else:
        sign = -1
        cursorInstanceClone.setFilter(sortField, '''<'%s' ''' % currentSort)
        cursorInstanceClone.orderBy('%s desc' % sortField)

    cursorInstanceClone.limit(0, abs(shift))
    countOfDownNodes = min(cursorInstanceClone.count(), abs(shift))
    for cursorInstanceClone in cursorInstanceClone.iterate():
        numberListChild = getattr(cursorInstanceClone, numberField).split('.')
        moveNodeInHierarchy(context, cursorInstanceClone, numberField, int(numberListChild[-1]) - sign)
    # Перемещаем указанный куст на свободную после перемещений позицию
    moveNodeInHierarchy(context, cursorInstance, numberField, int(numberList[-1]) + countOfDownNodes * sign)
    cursorInstanceClone.close()


def leftShiftNodeInHierarchy(context, cursorInstance, numberField, sortField):
    u'''Функция перемещает куст на один уровень выше'''
    currentNumber = getattr(cursorInstance, numberField)
    numberList = currentNumber.split('.')
    shiftNodeToOtherLevelInHierarchy(context, cursorInstance, numberField, sortField, '.'.join(numberList[:-2]))


def shiftNodeToOtherLevelInHierarchy(context, cursorInstance, numberField,
                                     sortField, parentNumber=None, isOneHierarchy=False):
    u'''Функция перемещает куст на уровень @parentNumber'''
    currentNumber = getattr(cursorInstance, numberField)
    numberList = currentNumber.split('.')
    parentNumberList = []
    # Создаем клон основного курсора и копируем в него фильтры
    cursorInstanceClone = cursorInstance.__class__(context)
    if not isOneHierarchy:
        cursorInstanceClone.copyFiltersFrom(cursorInstance)
    cursorInstanceClone.limit(0, 0)
    # Находим правильное место вставки
    if parentNumber:
        parentNumberList = parentNumber.split('.')
        cursorInstanceClone.setFilter(numberField, '''('%s.'%%)&(!'%s.'%%'.'%%)''' % (parentNumber, parentNumber))
    else:
        cursorInstanceClone.setFilter(numberField, '''(!%'.'%)''')
    level = len(numberList)
    if numberList == parentNumberList[:level]:
        raise CelestaException(u'''Невозможно сделать узел потомком себя и своих потомков''')
    elif numberList[:-1] == parentNumberList:
        return
    parentNumberList.append(unicode(cursorInstanceClone.count() + 1))
    # Перемещаем все узлы текущего куста кроме корня
    cursorInstanceClone.setFilter(numberField, '''('%s.'%%)''' % currentNumber)
    for cursorInstanceClone in cursorInstanceClone.iterate():
        numberListChild = getattr(cursorInstanceClone, numberField).split('.')
        cursorInstanceClone.__setattr__(numberField, '.'.join(parentNumberList + numberListChild[level:]))
        cursorInstanceClone.update()
    # Перемещаем корень текущего куста на правильную позицию
    currentSort = getattr(cursorInstance, sortField)
    cursorInstance.__setattr__(numberField, '.'.join(parentNumberList))
    cursorInstance.update()
    # Перемещаем все нижестоящие кусты относительно текущего на одну позицию вверх
    if '.' in currentNumber:
        sqlPattern = '''('%s.'%%)&(!'%s.'%%'.'%%)''' % ('.'.join(numberList[:-1]), '.'.join(numberList[:-1]))
    else:
        sqlPattern = '''(!%'.'%)'''
    cursorInstanceClone.setFilter(numberField, sqlPattern)
    cursorInstanceClone.setFilter(sortField, '''>'%s' ''' % currentSort)
    cursorInstanceClone.orderBy(sortField)
    for cursorInstanceClone in cursorInstanceClone.iterate():
        numberListChild = getattr(cursorInstanceClone, numberField).split('.')
        moveNodeInHierarchy(context, cursorInstanceClone, numberField, int(numberListChild[-1]) - 1)
    cursorInstanceClone.close()


def hasChildren(context, cursorInstance, numberField, isOneHierarchy=False):
    u'''Функция определяет наличие у элемента детей.'''
    currentNumber = getattr(cursorInstance, numberField)
    # Создаем клон основного курсора и копируем в него фильтры
    cursorInstanceClone = cursorInstance.__class__(context)
    if not isOneHierarchy:
        cursorInstanceClone.copyFiltersFrom(cursorInstance)
    cursorInstanceClone.limit(0, 0)
    cursorInstanceClone.setFilter(numberField, "'%s.'%%" % currentNumber)
    result = True if cursorInstanceClone.count() > 0 else False
    cursorInstanceClone.close()
    return result


def getNewItemInLevelInHierarchy(context, cursorInstance, numberField, isOneHierarchy=False):
    u'''Функция возвращает номер для нового элемента в указанном уровне иерархии'''
    currentNumber = getattr(cursorInstance, numberField)
    # Создаем клон основного курсора и копируем в него фильтры
    cursorInstanceClone = cursorInstance.__class__(context)
    if not isOneHierarchy:
        cursorInstanceClone.copyFiltersFrom(cursorInstance)
    cursorInstanceClone.limit(0, 0)
    # Отдельное условие, если вставляем на нулевой уровень иерархии
    if currentNumber is not None:
        cursorInstanceClone.setFilter(numberField, "('%s.'%%)&(!'%s.'%%'.'%%)" % (currentNumber, currentNumber))
        childCount = cursorInstanceClone.count()
        cursorInstanceClone.close()
        return '%s.%d' % (currentNumber, childCount + 1)
    else:
        cursorInstanceClone.setFilter(numberField, "!(%'.'%)")
        childCount = cursorInstanceClone.count()
        cursorInstanceClone.close()
        return unicode(childCount + 1)