/// <summary>
 /// Gets the audio text for the given element and send it immediately to the audio renderer.
 /// </summary>
 /// <param name="element">The element to get the text of.</param>
 /// <param name="additionalText">An additional text, that is put behind the element properties and befor the label (if available).</param>
 /// <returns>The describing string of the element in the following form: [ROLE] [NAME] (addintionalText)</returns>
 public static string PlayElementImmediately(OoAccComponent element, string additionalText = "")
 {
     String text = GetElementAudioText(element, additionalText);
     if (!String.IsNullOrWhiteSpace(text))
     {
         audio.PlaySoundImmediately(text);
     }
     return text;
 }
        /// <summary>
        /// Try to figure out if the accessible element is usable as interactive Shape
        /// </summary>
        /// <param name="element">The element.</param>
        /// <returns></returns>
        private static bool acceptAsUsableShape(OoAccComponent element)
        {
            if (element != null && element != null)
            {
                // check if the child is the paragraph
                if (element.ServiceNames.Contains(tud.mci.tangram.util.OO.Services.TEXT_ACCESSIBLE_PARAGRAPH))
                {
                    return false;
                }
                else
                {
                    if (element.Name.StartsWith("PageShape: "))
                    {
                        //TODO: decide if is a proper result
                        return false;
                    }
                }
            }

            return element != null;
        }
        /// <summary>
        /// Gets the OoShapeObserver for an accessible if already registered.
        /// </summary>
        /// <param name="accComp">The acc comp to get the observer for.</param>
        /// <param name="page">The page observer to search the observer in.</param>
        /// <returns>The related OoShapeObserver if already registered</returns>
        private static OoShapeObserver getObserverForAccessible(OoAccComponent accComp, OoDrawPageObserver page)
        {

            if (accComp != null && accComp.IsValid() && page != null)
            {
                var pObs = page.PagesObserver;
                if (pObs != null)
                {
                    OoShapeObserver sObs = pObs.GetRegisteredShapeObserver(accComp);

                    if (sObs == null) // shape is not registered
                    {
                        page.Update(); // try to do it better for the next term
                        AudioRenderer.Instance.PlayWaveImmediately(StandardSounds.Error);

                        ////TODO: try to get the parent
                        return null;
                    }

                    return sObs;
                }
                else
                {
                    Logger.Instance.Log(LogPriority.DEBUG, "OpenOfficeDrawShapeManipulator", "[ERROR] can't get the pages observer to get a ShapeObserver for the next item");
                }
            }
            return null;
        }
        private static OoAccComponent moveToChildComponent(OoAccComponent comp, ref int index)
        {
            if (comp != null && comp.IsValid() && comp.HasChildren)
            {
                try
                {
                    int childNumber = comp.ChildCount;
                    index = index % childNumber;

                    return comp.GetChild(index);

                }
                catch { }
            }

            return null;
        }
        private static OoAccComponent moveToParentComponent(OoAccComponent comp)
        {
            if (comp != null && comp.IsValid())
            {
                try
                {
                    OoAccComponent parent = comp.GetParent();
                    if (parent != null && acceptAsUsableShape(parent))
                    {
                        return parent;
                    }
                }
                catch { }
            }

            return null;
        }
        private static OoAccComponent moveToPrevComponent(OoAccComponent comp)
        {
            if (comp != null && comp.IsValid())
            {
                //--------------------------
                // try to get the parent
                OoAccComponent parent = comp.GetParent();
                if (parent != null)
                {
                    int pIndex = comp.IndexInParent;
                    int pcCount = parent.ChildCount;
                    int npIndex = mod(pIndex - 1, pcCount);

                    if (pIndex != npIndex)
                    {
                        // get prev sibling
                        var prevSibling = parent.GetChild(npIndex);
                        if (prevSibling != null)
                        {
                            System.Diagnostics.Debug.WriteLine("[MOVE PREV] ---> return prev sibling: " + prevSibling);
                            return prevSibling;
                        }
                    }
                }
            }

            return null;
        }
        /// <summary>
        /// Moves to prev component.
        /// </summary>
        /// <param name="comp">The comp.</param>
        /// <param name="handleChildren">if set to <c>true</c> [handle children].</param>
        /// <returns></returns>
        private static OoAccComponent moveDeterministicToPrevComponent(OoAccComponent comp, bool handleChildren = true)
        {
            if (comp != null)
            {
                //walk through the children and back to the parent
                //check if has children
                if (handleChildren && comp.HasChildren) // should have children --> go deeper
                {
                    //TODO: check if we accept this children - e.g. Text ???

                    // try get the first child
                    OoAccComponent child = comp.GetChild(comp.ChildCount - 1);
                    if (child != null)
                    {
                        System.Diagnostics.Debug.WriteLine("[MOVE PREV] ---> return child: " + child);
                        return child;
                    }
                }

                // if has no children --> go to prev sibling
                //--------------------------
                // try to get the parent
                OoAccComponent parent = comp.GetParent();
                if (parent != null)
                {
                    int pIndex = comp.IndexInParent;
                    if (pIndex >= 0)
                    {
                        int pcCount = parent.ChildCount;
                        if (pIndex > 0) // is not the first child
                        {
                            // get prev sibling
                            var prevSibling = parent.GetChild(pIndex - 1);
                            if (prevSibling != null)
                            {
                                System.Diagnostics.Debug.WriteLine("[MOVE PREV] ---> return prev sibling: " + prevSibling);
                                return prevSibling;
                            }
                        }
                        else // is first element --> go higher
                        {
                            return moveDeterministicToPrevComponent(parent, false);
                        }
                    }
                    else
                    {
                        // ERROR - this happens e.g. when the parent object is invalid
                        AudioRenderer.Instance.PlayWaveImmediately(StandardSounds.Error);
                        Logger.Instance.Log(LogPriority.OFTEN, "AccDomWalker", "[ERROR] Index in parent is negative");
                    }
                }
            }
            return null;
        }
        /// <summary>
        /// Gets the shape for modification.
        /// </summary>
        /// <param name="c">The c.</param>
        /// <param name="observed">The observed.</param>
        public OoShapeObserver GetShapeForModification(OoAccComponent c, OoAccessibleDocWnd observed)
        {
            if (observed != null && c.Role != AccessibleRole.INVALID)
            {
                //TODO: prepare name:

                //var shape = observed.DrawPagesObs.GetRegisteredShapeObserver(c.AccComp); 
                OoShapeObserver shape = observed.GetRegisteredShapeObserver(c);
                if (shape != null)
                {
                    if (shapeManipulatorFunctionProxy != null && !ImageData.Instance.Active)
                    {
                        OoElementSpeaker.PlayElementImmediately(shape, LL.GetTrans("tangram.lector.oo_observer.selected", String.Empty));
                        //audioRenderer.PlaySound("Form kann manipuliert werden");
                        shapeManipulatorFunctionProxy.LastSelectedShape = shape;
                        return shape;
                    }
                    else // title+desc dialog handling
                    {
                        ImageData.Instance.NewSelectionHandling(shape);
                    }
                }
                else
                {
                    // disable the pageShapes
                    if (c.Name.StartsWith("PageShape:"))
                    {
                        return null;
                    }

                    OoElementSpeaker.PlayElementImmediately(c, LL.GetTrans("tangram.lector.oo_observer.selected"));
                    audioRenderer.PlaySound(LL.GetTrans("tangram.lector.oo_observer.selected_element.locked"));
                }
            }
            return null;
        }
 /// <summary>
 /// Gets the registered shape observer.
 /// </summary>
 /// <param name="comp">The comp.</param>
 /// <returns></returns>
 public OoShapeObserver GetRegisteredShapeObserver(OoAccComponent comp)
 {
     return GetRegisteredShapeObserver(comp.AccCont);
 }
        /// <summary>
        /// Initializes a new instance of the <see cref="OoDrawPagesObserver"/> class.
        /// </summary>
        /// <param name="dp">The Draw document.</param>
        /// <param name="doc">The document related accessibility component.</param>
        /// <param name="docWnd">The related document accessible window component.</param>
        public OoDrawPagesObserver(XDrawPagesSupplier dp, OoAccComponent doc, OoAccessibleDocWnd docWnd = null)
        {
            this.PagesSupplier = dp;
            Document = doc;
            DocWnd = docWnd;

            // get Zoom and ViewOffset first time
            if (Controller != null)
            {
                if (Controller is XPropertySet)
                {
                    refreshDrawViewProperties((XPropertySet)(Controller));
                }
                // try to get dpi settings from openoffice
                XWindow componentWindow = Controller.ComponentWindow;
                if (componentWindow != null && componentWindow is XDevice)
                {
                    DeviceInfo deviceInfo = (DeviceInfo)((XDevice)componentWindow).getInfo();
                    if (deviceInfo != null)
                    {
                        PixelPerMeterX = deviceInfo.PixelPerMeterX;
                        PixelPerMeterY = deviceInfo.PixelPerMeterY;
                    }
                }
            }
            // register for Zoom and ViewOffset updates
            addVisibleAreaPropertyChangeListener();

            if (this.PagesSupplier != null)
            {
                List<XDrawPage> dpL = OoDrawUtils.DrawDocGetXDrawPageList(dp);

                if (PagesSupplier is unoidl.com.sun.star.frame.XTitle)
                {
                    Title = ((unoidl.com.sun.star.frame.XTitle)PagesSupplier).getTitle();
                }

                Logger.Instance.Log(LogPriority.DEBUG, this, "create DrawPagesObserver for supplier " + dp.GetHashCode() + " width title '" + Title + "' - having " + dpL.Count + " pages");

                //FIXME: Do this if the api enable parallel access
                //Parallel.ForEach(dpL, (drawPage) =>
                //{
                //    OoDrawPageObserver dpobs = new OoDrawPageObserver(drawPage, this);
                //    DrawPageobservers[drawPage] = dpobs;
                //    DrawPages.Add(dpobs);
                //});

                foreach (var drawPage in dpL)
                {
                    OoDrawPageObserver dpobs = new OoDrawPageObserver(drawPage, this);
                    RegisterDrawPage(dpobs);
                }

                XModifyBroadcaster mdfBc = PagesSupplier as XModifyBroadcaster;
                if (mdfBc != null)
                {
                    mdfBc.addModifyListener(eventForwarder);
                }
            }
        }
 /// <summary>
 /// Gets the registered shape observer to the accessible component if it is already registered.
 /// </summary>
 /// <param name="xAccessibleComponent">The x accessible component.</param>
 /// <returns>an accessible component if it is already registered</returns>
 public OoShapeObserver GetRegisteredShapeObserver(OoAccComponent accessibleComponent)
 {
     return GetRegisteredShapeObserver(accessibleComponent.AccComp);
 }
        /// <summary>
        /// Gets the audio text for the given element.
        /// </summary>
        /// <param name="element">The element to get the text of.</param>
        /// <param name="additionalText">An additional text, that is put behind the element properties</param>
        /// <returns>A string that should describe the element in the following form: [ROLE] [NAME] (addintionalText)</returns>
        public static String GetElementAudioText(OoAccComponent element, string additionalText = "")
        {
            String result = String.Empty;

            try
            {
                if (element != null)
                {
                    result += LL.GetTrans("tangram.oomanipulation.element_speaker.audio.element", element.Role.ToString(), element.Name.ToString(), additionalText.ToString());
                }
            }
            catch (System.Exception ex)
            {
                Logger.Instance.Log(LogPriority.DEBUG, "OoElementSpeaker", "[ERROR] Can't play element: " + ex);
            }

            return result;
        }