import os
import time

import uno

import player_presentation_errors
import player_presentation_utils


class OpenOffice(object):

    def __init__(self, executable, properties, log, host='localhost',
                 port=2002, start=True):
        self.log = log
        self.host = host
        self.executable = executable
        self.oo_pid = None
        self.port = port
        self.presentation = None
        self.properties = properties
        self.doc = None
        self.frame = None
        self.window = None

        if start:
            self.start_oo()
        self.create_oo_connection()
        self.toolkit = self.create_instance('com.sun.star.awt.Toolkit')
        self.create_window()
        self.create_frame()

    @player_presentation_utils.log_method
    def create_oo_connection(self):
        local_context = uno.getComponentContext()
        resolver = local_context.ServiceManager.createInstanceWithContext(
                        'com.sun.star.bridge.UnoUrlResolver', local_context)
        connected = False
        connectcount = 0
        while not connected:
            try:
                self.ctx = resolver.resolve('uno:socket,host=%s,port=%s;'
                    'urp;StarOffice.ComponentContext' % (self.host, self.port))
                connected = True
            except player_presentation_errors.NoConnectException:
                if connectcount == 0: 
                    self.log.debug("OOo not available, retrying...")
                if connectcount > 10:
                    self.log.debug("OOo not available, giving up.")
                    raise
                connectcount += 1
                time.sleep(1)
        self.smgr = self.ctx.ServiceManager

    @player_presentation_utils.log_method
    def start_oo(self):
        self.oo_pid = os.spawnl(os.P_NOWAIT,
                                self.executable,
                                'soffice',
                                '-accept=socket,host=%s,port=%s;urp;'
                                    % (self.host, self.port),
                                '-norestore',
                                '-invisible',
                                '-nofirststartwizard')

    @player_presentation_utils.log_method
    def create_window(self):
        WindowDescriptor = uno.getClass('com.sun.star.awt.WindowDescriptor')
        Rectangle = uno.getClass('com.sun.star.awt.Rectangle')

        loc = self.properties.get_location()
        rect = Rectangle(*loc)

        class WindowAttributeClass:
            def __getattr__(self, name):
                return uno.getConstantByName(
                    'com.sun.star.awt.WindowAttribute.%s' % name)
        WindowAttribute = WindowAttributeClass()

        wd = WindowDescriptor()
        wd.Bounds = rect
        wd.Parent = None
        wd.ParentIndex = -1
        wd.Type = uno.Enum('com.sun.star.awt.WindowClass', 'TOP')
        wd.WindowAttributes = (WindowAttribute.BORDER |
                               WindowAttribute.CLOSEABLE |
                               WindowAttribute.FULLSIZE |
                               WindowAttribute.MOVEABLE |
                               WindowAttribute.SIZEABLE |
                               WindowAttribute.SYSTEMDEPENDENT)
        wd.WindowServiceName = 'workwindow'
        self.window = self.toolkit.createWindow(wd)

    @player_presentation_utils.log_method
    def create_frame(self):
        self.frame = self.create_instance('com.sun.star.frame.Frame')
        self.frame.initialize(self.window)
        self.frame.LayoutManager = None

    @player_presentation_utils.log_method
    def move_offscreen(self):
        if self.window is not None:
            self.window.setPosSize(2000,2000,100,100,15)

    @player_presentation_utils.log_method
    def get_presentation(self, url):
        self.set_visible(False)
        self.doc = self.frame.loadComponentFromURL(url, '_self', 2, ())
        self.presentation = self.doc.getPresentation()
        return self.presentation

    @player_presentation_utils.log_method
    def set_visible(self, visible=True):
        if visible:
            self.set_location()
        else:
            self.move_offscreen()
            if self.window is not None:
                self.window.setVisible(True)

    @player_presentation_utils.log_method
    def set_location(self):
        x,y,w,h = self.properties.get_location()
        if self.window is not None:
            self.window.setPosSize(x, y, w, h, 15)

    @player_presentation_utils.log_method
    def create_instance(self, instance_type):
        self.log.debug(instance_type)
        return self.smgr.createInstanceWithContext(instance_type, self.ctx)

    @player_presentation_utils.log_method
    def terminate(self):
        if self.doc is not None:
            try:
                self.doc.close(False)
            except player_presentation_errors.DisposedException:
                pass
            self.doc = None
        for oo_obj in [self.frame, self.window]:
            if oo_obj is not None:
                try:
                    oo_obj.dispose()
                except player_presentation_errors.DisposedException:
                    pass
                oo_obj = None
        os.system('kill -9 %d' % (self.oo_pid,))

    def makePropertyValue(self,Name=None, Value=None, Handle=None, State=None ):
        # Create a com.sun.star.beans.PropertyValue struct and return it.
        PropertyValue = uno.getClass('com.sun.star.beans.PropertyValue')

        oPropertyValue = PropertyValue()

        if Name != None:
            oPropertyValue.Name = Name
        if Value != None:
            oPropertyValue.Value = Value
        if Handle != None:
            oPropertyValue.Handle = Handle
        if State != None:
            oPropertyValue.State = State

        return oPropertyValue

    def to_front(self):
        if self.window is not None:
            self.window.toFront()

    def to_back(self):
        if self.window is not None:
            self.window.toBack()

