/*
 * BRLTTY - A background process providing access to the console screen (when in
 *          text mode) for a blind person using a refreshable braille display.
 *
 * Copyright (C) 1995-2013 by The BRLTTY Developers.
 *
 * BRLTTY comes with ABSOLUTELY NO WARRANTY.
 *
 * This is free software, placed under the terms of the
 * GNU General Public License, as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any
 * later version. Please see the file LICENSE-GPL for details.
 *
 * Web Page: http://mielke.cc/brltty/
 *
 * This software is maintained by Dave Mielke <dave@mielke.cc>.
 */

package org.a11y.brltty.android;

import android.util.Log;

import java.util.List;
import java.util.ArrayList;

import android.os.Build;

import android.view.accessibility.AccessibilityNodeInfo;

import android.graphics.Rect;

public class RenderedScreen {
  private static final String LOG_TAG = RenderedScreen.class.getName();

  private final AccessibilityNodeInfo eventNode;
  private final AccessibilityNodeInfo rootNode;

  private final ScreenElementList screenElements = new ScreenElementList();
  private final List<CharSequence> screenRows = new ArrayList<CharSequence>();

  private int screenWidth = 1;

  public final AccessibilityNodeInfo getRootNode () {
    if (rootNode == null) return null;
    return AccessibilityNodeInfo.obtain(rootNode);
  }

  public final int getScreenWidth () {
    return screenWidth;
  }

  public final int getScreenHeight () {
    return screenRows.size();
  }

  public final CharSequence getScreenRow (int index) {
    return screenRows.get(index);
  }

  public final ScreenElement findScreenElement (AccessibilityNodeInfo node) {
    if (node == null) return null;
    Rect location = new Rect();
    node.getBoundsInScreen(location);
    return screenElements.findByVisualLocation(location);
  }

  public final ScreenElement findRenderedScreenElement (AccessibilityNodeInfo node) {
    ScreenElement element = findScreenElement(node);

    if (element != null) {
      if (element.getBrailleLocation() != null) {
        return element;
      }
    }

    {
      int childCount = node.getChildCount();

      for (int childIndex=0; childIndex<childCount; childIndex+=1) {
        AccessibilityNodeInfo child = node.getChild(childIndex);

        if (child != null) {
          element = findRenderedScreenElement(child);

          child.recycle();
          child = null;

          if (element != null) return element;
        }
      }
    }

    return null;
  }

  public final boolean performAction (int column, int row) {
    ScreenElement element = screenElements.findByBrailleLocation(column, row);

    if (element != null) {
      if (element.performAction(column - element.getBrailleLocation().left)) {
        return true;
      }
    }

    return false;
  }

  private final int addScreenElements (AccessibilityNodeInfo root) {
    final int significantActions = AccessibilityNodeInfo.ACTION_CLICK
                                 | AccessibilityNodeInfo.ACTION_LONG_CLICK
                                 | AccessibilityNodeInfo.ACTION_SCROLL_FORWARD
                                 | AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD
                                 ;
    int propagatedActions = significantActions;

    if (root != null) {
      int actions = root.getActions() & significantActions;

      {
        int childCount = root.getChildCount();

        if (childCount > 0) {
          propagatedActions = 0;

          for (int childIndex=0; childIndex<childCount; childIndex+=1) {
            AccessibilityNodeInfo child = root.getChild(childIndex);

            if (child != null) {
              propagatedActions |= addScreenElements(child);

              child.recycle();
              child = null;
            }
          }
        }
      }

      boolean isVisible;
      if (ApplicationUtilities.haveSdkVersion(Build.VERSION_CODES.JELLY_BEAN)) {
        isVisible = root.isVisibleToUser();
      } else {
        Rect location = new Rect();
        root.getBoundsInScreen(location);
        isVisible = ScreenDriver.getWindow().contains(location);
      }

      if (isVisible) {
        String text = ScreenUtilities.normalizeText(root.getText());
        String description = ScreenUtilities.normalizeText(root.getContentDescription());

        if (text != null) {
          if (description != null) text = description;
        } else if (actions != 0) {
          if (((actions & propagatedActions) != actions) || (root.getChildCount() == 0)) {
            if ((text = description) == null) {
              text = root.getClassName().toString();
              int index = text.lastIndexOf('.');
              if (index >= 0) text = text.substring(index+1);
              text = "(" + text + ")";
            }
          }
        }

        if (text == null) text = "";
        screenElements.add(text, root);
      }

      propagatedActions &= ~actions;
    }

    return propagatedActions;
  }

  private final void finishScreenRows () {
    if (screenRows.isEmpty()) {
      screenRows.add("waiting for screen update");
    }

    for (CharSequence row : screenRows) {
      int length = row.length();

      if (length > screenWidth) {
        screenWidth = length;
      }
    }
  }

  public RenderedScreen (AccessibilityNodeInfo node) {
    if (node != null) node = AccessibilityNodeInfo.obtain(node);

    eventNode = node;
    rootNode = ScreenUtilities.findRootNode(node);

    addScreenElements(rootNode);
    BrailleRenderer.getBrailleRenderer().renderScreenElements(screenRows, screenElements);
    finishScreenRows();
  }
}

@@ -3404,19 +3404,8 @@
 ns;%0A
-%0A      %7B%0A  
     
@@ -3444,34 +3444,32 @@
 Count();%0A%0A      
-  
 if (childCount %3E
@@ -3470,26 +3470,24 @@
 ount %3E 0) %7B%0A
-  
         prop
@@ -3510,26 +3510,24 @@
 0;%0A%0A        
- 
- 
 for (int chi
@@ -3583,26 +3583,24 @@
 %7B%0A          
-  
 Accessibilit
@@ -3641,26 +3641,24 @@
 ildIndex);%0A%0A
-  
           if
@@ -3684,26 +3684,24 @@
             
-  
 propagatedAc
@@ -3740,34 +3740,32 @@
 );%0A%0A            
-  
 child.recycle();
@@ -3769,34 +3769,32 @@
 ();%0A            
-  
 child = null;%0A  
@@ -3791,30 +3791,16 @@
 = null;%0A
-            %7D%0A
         
@@ -4501,25 +4501,17 @@
 ns) %7C%7C (
-root.getC
+c
 hildCoun
@@ -4511,18 +4511,16 @@
 ildCount
-()
  == 0)) 

Simplify a bit of code. (dm)