#!/usr/bin/env python3

import uno
import unohelper
from com.sun.star.io import IOException, XOutputStream
from .easymain import (log,
    BaseObject, LOMain, Paths,
    dict_to_property, create_instance
)


class IOStream(object):
    """Classe for input/output stream"""

    class OutputStream(unohelper.Base, XOutputStream):

        def __init__(self):
            self._buffer = b''
            self.closed = 0

        @property
        def buffer(self):
            return self._buffer

        def closeOutput(self):
            self.closed = 1

        def writeBytes(self, seq):
            if seq.value:
                self._buffer = seq.value

        def flush(self):
            pass

    @classmethod
    def buffer(cls):
        return io.BytesIO()

    @classmethod
    def input(cls, buffer):
        service = 'com.sun.star.io.SequenceInputStream'
        stream = create_instance(service, True)
        stream.initialize((uno.ByteSequence(buffer.getvalue()),))
        return stream

    @classmethod
    def output(cls):
        return cls.OutputStream()


class LODocument(BaseObject):

    def __init__(self, obj):
        super().__init__(obj)
        self._cc = obj.getCurrentController()
        self._undo = True

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        self.close()

    @property
    def type(self):
        """Get type document"""
        return self._type

    @property
    def title(self):
        """Get title document"""
        return self.obj.getTitle()
    @title.setter
    def title(self, value):
        self.obj.setTitle(value)

    @property
    def uid(self):
        """Get Runtime UID"""
        return self.obj.RuntimeUID

    @property
    def is_saved(self):
        """Get is saved"""
        return self.obj.hasLocation()

    @property
    def is_modified(self):
        """Get is modified"""
        return self.obj.isModified()

    @property
    def is_read_only(self):
        """Get is read only"""
        return self.obj.isReadonly()

    @property
    def path(self):
        """Get path in system files"""
        return Paths.to_system(self.obj.URL)

    @property
    def dir(self):
        """Get directory from path"""
        return Paths(self.path).path

    @property
    def file_name(self):
        """Get only file name"""
        return Paths(self.path).file_name

    @property
    def name(self):
        """Get name without extension"""
        return Paths(self.path).name

    @property
    def visible(self):
        """Get windows visible"""
        w = self.frame.ContainerWindow
        return w.isVisible()
    @visible.setter
    def visible(self, value):
        w = self.frame.ContainerWindow
        w.setVisible(value)

    @property
    def zoom(self):
        """Get current zoom value"""
        return self._cc.ZoomValue
    @zoom.setter
    def zoom(self, value):
        self._cc.ZoomValue = value

    @property
    def status_bar(self):
        """Get status bar"""
        bar = self._cc.getStatusIndicator()
        return bar

    @property
    def selection(self):
        """Get current selecction"""
        sel = self.obj.CurrentSelection
        return sel

    @property
    def frame(self):
        """Get frame document"""
        return self._cc.getFrame()

    def _create_instance(self, name):
        obj = self.obj.createInstance(name)
        return obj

    def save(self, path: str='', args: dict={}) -> bool:
        """Save document

        :param path: Path to save document
        :type path: str
        :param args: Optional: Extra argument for save
        :type args: dict
        :return: True if save correctly, False if not
        :rtype: bool
        """
        if not path:
            self.obj.store()
            return True

        path_save = Paths.to_url(path)
        opt = dict_to_property(args)
        print(opt)

        try:
            self.obj.storeAsURL(path_save, opt)
        except Exception as e:
            log.error(e)
            return False

        return True

    def close(self):
        """Close document"""
        self.obj.close(True)
        return

    def to_pdf(self, path: str='', args: dict={}):
        """Export to PDF

        :param path: Path to export document
        :type path: str
        :param args: Optional: Extra argument for export
        :type args: dict
        :return: None if path or stream in memory
        :rtype: bytes or None

        `See PDF Export <https://wiki.documentfoundation.org/Macros/Python_Guide/PDF_export_filter_data>`_
        """
        stream = None
        path_pdf = 'private:stream'

        filter_name = f'{self.type}_pdf_Export'
        filter_data = dict_to_property(args, True)
        filters = {
            'FilterName': filter_name,
            'FilterData': filter_data,
        }
        if path:
            path_pdf = Paths.to_url(path)
        else:
            stream = IOStream.output()
            filters['OutputStream'] = stream

        opt = dict_to_property(filters)
        try:
            self.obj.storeToURL(path_pdf, opt)
        except Exception as e:
            error(e)

        if not stream is None:
            stream = stream.buffer

        return stream

    def export(self, path: str='', filter_name: str='', args: dict={}):
        """Export to others formats

        :param path: Path to export document
        :type path: str
        :param filter_name: Filter name to export
        :type filter_name: str
        :param args: Optional: Extra argument for export
        :type args: dict
        :return: None if path or stream in memory
        :rtype: bytes or None
        """
        FILTERS = {
            'xlsx': 'Calc MS Excel 2007 XML',
            'xls': 'MS Excel 97',
            'docx': 'MS Word 2007 XML',
            'doc': 'MS Word 97',
            'rtf': 'Rich Text Format',
        }

        stream = None
        path_target = 'private:stream'

        filter_name = FILTERS.get(filter_name, filter_name)
        filter_data = dict_to_property(args, True)
        filters = {
            'FilterName': filter_name,
            'FilterData': filter_data,
        }
        if path:
            path_target = Paths.to_url(path)
        else:
            stream = IOStream.output()
            filters['OutputStream'] = stream

        opt = dict_to_property(filters)
        try:
            self.obj.storeToURL(path_target, opt)
        except Exception as e:
            error(e)

        if not stream is None:
            stream = stream.buffer

        return stream

    def set_focus(self):
        """Send focus to windows"""
        w = self.frame.ComponentWindow
        w.setFocus()
        return

    def copy(self):
        """Copy current selection"""
        LOMain.dispatch(self.frame, 'Copy')
        return

    def paste(self):
        """Paste current content in clipboard"""
        sc = create_instance('com.sun.star.datatransfer.clipboard.SystemClipboard')
        transferable = sc.getContents()
        self._cc.insertTransferable(transferable)
        return

    def paste_special(self):
        """Insert contents, show dialog box Paste Special"""
        LOMain.dispatch(self.frame, 'InsertContents')
        return

    def paste_values(self):
        """Paste only values"""
        args = {
            'Flags': 'SVD',
            # ~ 'FormulaCommand': 0,
            # ~ 'SkipEmptyCells': False,
            # ~ 'Transpose': False,
            # ~ 'AsLink': False,
            # ~ 'MoveMode': 4,
        }
        LOMain.dispatch(self.frame, 'InsertContents', args)
        return

    def clear_undo(self):
        """Clear history undo"""
        self.obj.getUndoManager().clear()
        return


class LODrawImpress(LODocument):

    def __init__(self, obj):
        super().__init__(obj)
