# coding: utf-8

import java.io.OutputStreamWriter as OutputStreamWriter
import java.io.InputStreamReader as InputStreamReader
import java.io.BufferedReader as BufferedReader
from java.io import FileOutputStream, ByteArrayOutputStream, FileInputStream, File
import base64
import uuid
import json
from common.sysfunctions import toHexForXml
from importlib import import_module

try:
    from ru.curs.showcase.core.jython import JythonDownloadResult
    from ru.curs.showcase.core.jython import JythonErrorResult
except:
    pass

g_importCache = {}

def getCursorDeweyColumns(table_meta):
    """Ищет в метаданных поля для работы с Дьюи: столбец кода и сортировки.
    
    Если такие имена столбцов не найдены, по умолчанию считается, что такими 
    являются поля курсора **deweyCode** и **deweySort** 
    
    @param table_meta метаданные курсора Celesta 
    @return (tuple of (string, string)) 0 - поле кода Дьюи, 1 - поле сортировки
    Дьюи 
    """
    deweyColumn = 'deweyCode'
    sortColumn = 'deweySort'
    
    for column in table_meta.getColumns():
        cDoc = {}
        try:
            cDoc = json.loads(table_meta.getColumn(column).getCelestaDoc())
        except:
            continue
            #получаем названиe колонкu с кодом дьюи 
        if cDoc['name'] in (u'deweyCode', u'deweyCod', u'deweyKod'):
            deweyColumn = column
        if cDoc['name'] == u'sortNumber':
            sortColumn = column
            
    return deweyColumn, sortColumn

def importcache(func):
    def wrapper(grain_name, table_name):
        try:
            return g_importCache[(grain_name, table_name)]
        except KeyError:
            res = func(grain_name, table_name)
            g_importCache[(grain_name, table_name)] = res 
            return res
        
        raise Exception('Error during import cache!')
    
    return wrapper

@importcache
def relatedTableCursorImport(grain_name, table_name):
    u'''Функция, выдающая класс курсора на таблицу, связанную с выбранным справочником 
    
    Еcли table_name в формате <grain>.<table>, то имя гранулы берётся из table_name.
    Если table_name без указания гранулы, то используется grain_name.
    '''
    tn = table_name
    gn = table_name.split('.')
    if len(gn) == 1:
        gn = grain_name  
    elif len(gn) == 2:
        tn = gn[1]
        gn = gn[0]
    else:
        raise Exception('Incorrect table name: <table> or <grain>.<table> expected but %s given.' % str(table_name))
    
    # Модуль, откуда импортируем класс курсора
    name = '%s._%s_orm' % (gn, gn)
    
    return getattr(import_module(name), tn + "Cursor")
#     # Название класса курсора
#     fromlist = ['%sCursor' % table_name]
#     return getattr(__import__(name, globals(), locals(), fromlist, -1), fromlist[0])




def getFieldsHeaders(table_meta, elem_type):
    u'''Функция для получения соответствия между реальными именами полей
    и заголовками в гриде.
    
    Возвращает словарь вида:
        {<Имя поля>: 
            [<Имя столбца для XML>,    #индекс 0 
            <ИД типа>,                 #индекс 1
            <Порядок>,                 #индекс 2
            <Имя столбца>,             #индекс 3
            <Ширина столбца>           #индекс 4
            ]
        }
    '''
    colWidth=''
    # Заносим служебные поля
    _headers = {'~~id':['~~id', 0, 0, '~~id']}

    # Получаем список имён столбцов из метаданных
    col_names = table_meta.getColumns()
    # Проходим по каждому столбцу и получаем его CelestDoc
    for col_name in col_names:
        try:
            column_jsn = json.loads(table_meta.getColumn(col_name).getCelestaDoc())
            # Проверка на видимость столбца если грид
            if elem_type == "grid":
                if column_jsn["visualLength"] != '0':
                    #задание ширины столбцов
                    try:
                        colWidth = '%spx' %int(column_jsn["visualLength"])
                    #если ширина не задана в celestaDoc, по умолчанию
                    except ValueError:
                        colWidth = ''
                else:
                    continue
            _headers[col_name] = [column_jsn["name"], int(column_jsn["fieldTypeId"]), int(column_jsn["fieldOrderInSort"]), column_jsn["name"], colWidth]
        #Если неверно задан челестадок
        except:
            continue
    for col in _headers:
        _headers[col][0] = toHexForXml(_headers[col][0])

    return _headers

def getSortList(table_meta):
    u'''Функция для получения списка порядковых номеров полей для сортировки'''

    # Аналог в 1 строку без проверки на int не int
    #sort_list = map(lambda x: int(json.loads(table_meta.getColumn(x).getCelestaDoc())["fieldOrderInGrid"]), table_meta.getColumns())

    sort_list = []
    col_names = table_meta.getColumns()
    for col_name in col_names:
        try:
            column_meta = json.loads(table_meta.getColumn(col_name).getCelestaDoc())
            sort_number = int(column_meta["fieldOrderInSort"])
            if column_meta["visualLength"] == '0':
                continue
            else:
                sort_list.append(sort_number)
        except:
            continue
    return sorted(sort_list)

def findJsonValues(element, obj):
    u'''Рекурсивная функция для получения элемента внутри json '''
    results = []
    def _findJsonValues(element, obj):
        try:
            for key, value in obj.iteritems():
                if key == element:
                    results.append(value)
                elif not isinstance(value, basestring):
                    _findJsonValues(element, obj)
        except AttributeError:
            pass

        try:
            for item in obj:
                if not isinstance(item, basestring):
                    _findJsonValues(element, obj)
        except TypeError:
            pass

    if not isinstance(obj, basestring):
        _findJsonValues(element, obj)
    return results

def htmlDecode(string):
    return string.replace('_x0020_', ' ').replace('_x002e_', '.').replace('_x002d_', '-').replace('_x0451_', u'ё').replace('_x0401_', u'Ё')

def readLongTextData(cursor, fieldname):
    u'''Функция для чтения полей типа Longtext. '''

    getattr(cursor, 'calc%s' % fieldname)()
    inr = BufferedReader(InputStreamReader(getattr(cursor, fieldname).getInStream(), 'utf-8'))
    filedata = ""
    while 1:
        onechar = inr.read()
        if onechar != -1:
            filedata += unichr(onechar)
        else:
            break
    return filedata

def insertLongTextData(cursor, fieldname, data):
    u'''Функция вставки Longtext в поле fieldname. '''

    # cursor.init() нужно ли это?
    getattr(cursor, 'calc%s' % fieldname)()
    osw = OutputStreamWriter(getattr(cursor, fieldname).getOutStream(), 'utf-8')
    try:
        osw.append(data)
    finally:
        osw.close()

    cursor.insert()

def downloadFileFromGrid(context, main=None, add=None, filterinfo=None,
                  session=None, elementId=None, recordId=None, columnId=None):
    u'''Функция для скачивания файла из грида. '''

    #raise Exception(json.loads(base64.b64decode(recordId)))
    grain_name = json.loads(main)['grain']
    table_name = json.loads(main)['table']
    # Получение курсора на таблицу
    currentTable = relatedTableCursorImport(grain_name, table_name)(context)
    # Наводим курсор на текущую запись
    currentTable.get(json.loads(base64.b64decode(recordId)))
    # picture указана временно, пока columnId не реализован
    getattr(currentTable, 'calcattachment')()
    data = getattr(currentTable, 'attachment').getInStream()
    # Имя файла - расширение лучше указывать в отдельном поле в таблице
    fileName = '123.xml'
    #data = open('C:\\eclipse\eclipse.ini')
    # Если в потоке что-то есть, тогда вызываем скачивание файла
    if data:
        try:
            return JythonDownloadResult(data, fileName)
        except:
            return None


def downloadFileFromXform(context, main=None, add=None, filterinfo=None,
                  session=None, elementId=None, xformsdata=None, columnId=None):
    u'''Функция для скачивания файла из карточки. '''

    grain_name = json.loads(main)['grain']
    table_name = json.loads(main)['table']
    # Получение курсора на таблицу
    currentTable = relatedTableCursorImport(grain_name, table_name)(context)
    # Наводим курсор на текущую запись
    currentTable.get(json.loads(xformsdata)["schema"]["row"])
    # Пока что столбец - picture, далее через columnId
    getattr(currentTable, 'calcattachment')()
    # Создаем поток
    data = getattr(currentTable, 'attachment').getInStream()
    # Имя файла - расширение лучше указывать в отдельном поле в таблице
    fileName = '%s.xml' % currentTable.text
    # Если в потоке что-то есть, тогда вызываем скачивание файла
    if data:
        return JythonDownloadResult(data, fileName)

def uploadFileToXform(context, main, add, filterinfo, session, elementId, xformsdata, fileName, file1):
    u'''Функция для загрузки файла из формы в БД. '''
    '''context, main, add, filterinfo, session, elementId, xformsdata, fileName, file1'''

    grain_name = json.loads(main)['grain']
    table_name = json.loads(main)['table']
    newfileid = ''
    #raise Exception(xformsdata,session)
    try:
        currentRecordId = json.loads(session)['sessioncontext']['related']['gridContext']['currentRecordId']
        selectedRecordId = json.loads(base64.b64decode(str(currentRecordId)))
    except:
        context.warning("Error: cannot get Current record id")
    # Получение курсора на таблицу
    currentTable = relatedTableCursorImport(grain_name, table_name)(context)
    fields = currentTable.meta().getColumns()
    fileid = None
    if 'currentRecordId' in json.loads(session)['sessioncontext']['related']['gridContext']:
        currentRecordId = json.loads(session)['sessioncontext']['related']['gridContext']['currentRecordId']
        selectedRecordId = json.loads(base64.b64decode(str(currentRecordId)))
        currentTable.get(*selectedRecordId)
    for field in fields:
        column_jsn = json.loads(currentTable.meta().getColumn(field).getCelestaDoc())
        if column_jsn["fieldTypeId"] == "4":
            filecolumn = field
            if "refTable" in column_jsn:
                refTableName = column_jsn["refTable"]
                refTableColumnId = column_jsn["refTableColumnId"]
                refFileColumn = column_jsn["refFileColumn"]
                relatedTable = relatedTableCursorImport(grain_name, refTableName)(context)
                fileid = getattr(currentTable, filecolumn)
                if fileid != None:
                    relatedTable.setRange(refTableColumnId, fileid)
                    relatedTable.first()
                else:
                    newfileid = uuid.uuid4()
                    setattr(relatedTable, refTableColumnId, newfileid)
                    setattr(currentTable, filecolumn, newfileid)
            break
    # Переводим курсор на запись

    try:
        if newfileid != '':
            getattr(relatedTable, 'calc' + refFileColumn)()
        else:
            getattr(currentTable, 'calc' + filecolumn)()
    except:
        context.error("Error: cannot calculate blob file. Column %s Table %s" % (refFileColumn, refTableName))
    # Поток для записи файла в базу

    try:
        if newfileid != '':
            outputstream = OutputStreamWriter(getattr(relatedTable, refFileColumn).getOutStream(), 'utf-8')
        else:
            outputstream = OutputStreamWriter(getattr(currentTable, filecolumn).getOutStream(), 'utf-8')
    except:
        context.error("Error: cannot create outputstream object")

    #outputstream = getattr(currentTable, 'attachment').getOutStream()
    # Промежуточный поток

    # Побайтово читаем поток файла и пишем его в baos
    while 1:
        #i=i+1
        try:
            onebyte = file1.read()
        except:
            context.error("Error: cannot read from file to import")
        if onebyte != -1:
            try:
                outputstream.write(onebyte)
            except:
                context.error("Error: cannot write binary data to table during import. filecolumn is %s, data %s" % (filecolumn, onebyte))
        else:
            break
    #raise Exception (str(i))
    if newfileid != '':
        relatedTable.insert()
        currentTable.update()


    else:
        currentTable.update()
    context.message("File uploaded successfully")
    #return JythonErrorResult()