# -*- coding: Latin-1 -*-
#
# This file created Oct 26 2012 by Jim Kornelsen
#
# 17-Dec-12 JDK  Include both input and output.
# 01-Mar-13 JDK  Fixed bug: 0-length list was selecting two (A2:A1).
# 23-Jul-15 JDK  Refactor outputList().
# 25-Aug-15 JDK  Fixed bug: %d does not accept a string.

"""
Word list input and output for Calc.
"""
import logging
from com.sun.star.uno import RuntimeException

from lingt.access.calc.spreadsheet_output import SpreadsheetOutput
from lingt.access.calc.spreadsheet_reader import SpreadsheetReader
from lingt.app import exceptions
from lingt.app.data.wordlist_structs import WordInList
from lingt.ui.common.messagebox import MessageBox
from lingt.ui.common.progressbar import ProgressBar, ProgressRanges
from lingt.utils import util
from lingt.utils.locale import theLocale

logger = logging.getLogger("lingt.access.wordlist_io")

class WordlistIO:
    def __init__(self, calcUnoObjs, colOrder):
        self.unoObjs = calcUnoObjs
        self.colOrder = colOrder
        self.msgbox = MessageBox(self.unoObjs)
        self.progressRanges = None
        self.sheet = None
        self.listDoc = None

    def getMsgbox(self):
        """After outputList(), self.msgbox will be for the spreadsheet."""
        return self.msgbox

    def outputList(self, wordList, progressBarWriter):
        """Sends output to the Calc spreadsheet.
        Takes a list of app.wordlist.WordInList.
        """
        logger.debug(util.funcName('begin'))
        outputter = SpreadsheetOutput(self.unoObjs)
        self.listDoc = outputter.createSpreadsheet()
        self.msgbox = MessageBox(self.listDoc)
        self.sheet = self.listDoc.sheets.getByIndex(0)

        progressBarCalc = ProgressBar(self.listDoc, "Generating List...")
        progressBarCalc.show()
        self.progressRanges = ProgressRanges(
            [progressBarWriter, progressBarCalc])
        self.progressRanges.initRanges(
            progressBarWriter.getPercent() + 20, 95, len(wordList))
        self.progressRanges.updateStart()
        try:
            self._outputList(wordList)
            self.progressRanges.updateFinishing()
        finally:
            self.progressRanges.closeBars()
        logger.debug(util.funcName('end'))

    def _outputList(self, wordList):
        headingRow = 0     # first row
        numberFormat = 0     # General format
        for colNum, heading in enumerate(self.colOrder.getTitles()):
            cell = self.sheet.getCellByPosition(colNum, headingRow)
            cell.setFormula("")
            cell.setPropertyValue("NumberFormat", numberFormat)
            cell.setString(theLocale.getText(heading))

        cellFreeze = self.sheet.getCellByPosition(0, 1)
        self.listDoc.controller.select(cellFreeze)
        self.unoObjs.dispatcher.executeDispatch(
            self.listDoc.frame, ".uno:FreezePanes", "", 0, ())

        CHUNK_SIZE = 25  # make this value bigger or smaller for optimization
        #CHUNK_SIZE = 1  # useful for debugging
        for word_i1 in range(0, len(wordList), CHUNK_SIZE):
            word_i2 = word_i1 + CHUNK_SIZE - 1
            if word_i2 >= len(wordList):
                word_i2 = len(wordList) - 1
            self._fillInData(wordList, word_i1, word_i2)

    def _fillInData(self, wordList, word_i1, word_i2):
        data = []
        for word_i in range(word_i1, word_i2 + 1):
            word = wordList[word_i]
            colOrd = self.colOrder  # shorthand variable name
            colOrd.resetRowData()
            colOrd.setRowVal('colWord', word.text)
            colOrd.setRowVal('colOccur', word.occurrences)
            colOrd.setRowVal('colOk', word.isCorrect_str())
            colOrd.setRowVal('colChange', word.correction)
            colOrd.setRowVal('colSrc', word.sources_str())
            data.append(colOrd.getRowTuple())

        row1 = word_i1 + 2  # start at second row, so index 0 is row 2
        row2 = word_i2 + 2
        col2 = chr(ord('A') + len(self.colOrder.COLUMNS) - 1)
        rangeName = "A%d:%s%d" % (row1, col2, row2)
        logger.debug("Adding %d rows to range %s", len(data), rangeName)
        #logger.debug(repr(data))
        oRange = self.sheet.getCellRangeByName(rangeName)
        try:
            oRange.setDataArray(tuple(data))
        except RuntimeException as exc:
            raise exceptions.FileAccessError(
                "There was a problem while writing the list.\n\n%s", exc)
        self.progressRanges.update(word_i1)

    def readList(self):
        """Expects input spreadsheet to have columns generated by
        word list app,
        including word, similar words, source, isCorrect, et cetera.
        Returns a list of app.wordlist.WordInList.
        """
        logger.debug(util.funcName('begin'))

        colOrd = self.colOrder  # shorthand variable name
        colLetterWord = colOrd.getColLetter('colWord')
        reader = SpreadsheetReader(self.unoObjs)
        stringList = reader.getColumnStringList(colLetterWord, True)
        if len(stringList) == 0:
            logger.debug("No data found.")
            return []
        row1 = 2    # first row is heading, second row is beginning of data
        row2 = row1 + len(stringList) - 1
        rangeName = "%s%d:%s%d" % ('A', row1, colOrd.maxColLetter(), row2)
        try:
            oRange = self.unoObjs.sheet.getCellRangeByName(rangeName)
            rowTuples = oRange.getDataArray()
        except RuntimeError as exc:
            self.msgbox.display("Error reading the list.\n\n%s", str(exc))
            return []
        if len(rowTuples) == 0:
            logger.debug("Could not get data.")
            return []

        datalist = []
        for rowTuple in rowTuples:
            colOrd.setRowTuple(rowTuple)
            wordInList = WordInList()
            wordInList.text = colOrd.getRowVal('colWord')
            wordInList.occurrences = colOrd.getRowVal('colOccur')
            wordInList.correction = colOrd.getRowVal('colChange')
            wordInList.converted1 = colOrd.getRowVal('colConv1')
            wordInList.converted2 = colOrd.getRowVal('colConv2')
            wordInList.setSources(colOrd.getRowVal('colSrc'))
            wordInList.setSimilarWords(colOrd.getRowVal('colSimilar'))
            wordInList.setIsCorrect(colOrd.getRowVal('colOk'))
            datalist.append(wordInList)
        return datalist


class ProgressBars:
    """Keeps Writer and Calc bars in sync."""
    def __init__(self):
        self.calc = None
        self.writer = None
        self.start_val = 0
