package silence.com.cn.a310application.appanalyst;

import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.accessibility.AccessibilityNodeInfo;

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

public class UiNode {
    private AccessibilityNodeInfo mAccessibilityNodeInfo;
    private String mClassName;
    private String mText;
    private String mDescription;
    private final ArrayList<UiNode> mChilds = new ArrayList<>();
    private int mFormIndex = -1;

    public static class NullChildAccessibilityNodeInfoException extends MyException {
        public NullChildAccessibilityNodeInfoException() {
            super();
        }

        public NullChildAccessibilityNodeInfoException(String detailMessage) {
            super(detailMessage);
        }

        public NullChildAccessibilityNodeInfoException(String detailMessage, Throwable throwable) {
            super(detailMessage, throwable);
        }

        public NullChildAccessibilityNodeInfoException(Throwable throwable) {
            super(throwable);
        }
    }

    public UiNode(@NonNull AccessibilityNodeInfo accessibilityNodeInfo) throws NullChildAccessibilityNodeInfoException, MyException {
        if (null == accessibilityNodeInfo) {
            throw new NullPointerException("accessibilityNodeInfo");
        }
        try {
            mAccessibilityNodeInfo = accessibilityNodeInfo;
            mClassName = StringUtil.toEb(accessibilityNodeInfo.getClassName());
            mText = StringUtil.toNb(accessibilityNodeInfo.getText());
            mDescription = StringUtil.toNb(accessibilityNodeInfo.getContentDescription());
            int count = accessibilityNodeInfo.getChildCount();
            for (int i = 0; i < count; i++) {
                AccessibilityNodeInfo childAccessibilityNodeInfo = accessibilityNodeInfo.getChild(i);
                if (null == childAccessibilityNodeInfo) {
                    throw new NullChildAccessibilityNodeInfoException("出现空的子AccessibilityNodeInfo");
                }
                mChilds.add(new UiNode(childAccessibilityNodeInfo));
            }
        } catch (NullChildAccessibilityNodeInfoException e) {
            throw e;
        } catch (MyException e) {
            throw e;
        } catch (Exception e) {
            throw new MyException(e);
        }
    }

    public void recycle() {
        for (UiNode childNode : mChilds) {
            childNode.recycle();
        }
        if (null != mAccessibilityNodeInfo) {
            mAccessibilityNodeInfo.recycle();
        }
    }

    @NonNull
    public String getClassName() {
        return mClassName;
    }

    @Nullable
    public String getText() {
        return mText;
    }

    @Nullable
    public String getDescription() {
        return mDescription;
    }

    @NonNull
    public Iterator<UiNode> childIterator() {
        return mChilds.iterator();
    }

    public int getChildCount() {
        return mChilds.size();
    }

    @Nullable
    public UiNode getChild(int index) {
        try {
            return mChilds.get(index);
        } catch (Exception e) {
            return null;
        }
    }

    public void setFormIndex(int index) {
        mFormIndex = index;
    }

    public int getFormIndex() {
        return mFormIndex;
    }

    @Nullable
    public List<UiNode> findChildsByText(@NonNull String text) {
        if (null == text) {
            throw new NullPointerException("text");
        }
        List<UiNode> childs = new ArrayList<>();
        findChildsByText(childs, this, text);
        return childs;
    }

    private static void findChildsByText(@NonNull List<UiNode> childs, @NonNull UiNode uiNode, @NonNull String text) {
        if (null == childs) {
            throw new NullPointerException("childs");
        }
        if (null == uiNode) {
            throw new NullPointerException("uiNode");
        }
        if (null == text) {
            throw new NullPointerException("text");
        }
        if (uiNode.getText().equals(text)) {
            childs.add(uiNode);
        }
        for (UiNode child : uiNode.mChilds) {
            child.findChildsByText(childs, child, text);
        }
    }

    @Nullable
    public UiNode getNode(@NonNull int[] path) throws MyException {
        return getNode(path, 0);
    }

    @Nullable
    private UiNode getNode(@NonNull int[] path, int level) throws MyException {
        if (null == path) {
            throw new NullPointerException("path");
        }
        if (path.length <= level) {
            throw new MyException("路径表示异常");
        }
        if (0 == level) {
            if (0 != path[0]) {
                throw new MyException("路径表示错误");
            }
        }
        if (path.length == level + 1) {
            return this;
        }
        int index = path[level + 1];
        for (UiNode child : mChilds) {
            if (child.getFormIndex() == index) {
                return child.getNode(path, level + 1);
            }
        }
        return null;
    }

    public void click() throws MyException {
        try {
            mAccessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);
        } catch (Exception e) {
            throw new MyException(e);
        }
    }

    public void longClick() throws MyException {
        try {
            mAccessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_LONG_CLICK);
        } catch (Exception e) {
            throw new MyException(e);
        }
    }

    public void setEditText(@NonNull Context context, @NonNull String text) throws MyException {
        if (null == context) {
            throw new NullPointerException("context");
        }
        if (null == text) {
            throw new NullPointerException("text");
        }
        try {
            //清空内容
            Bundle arguments = new Bundle();
            arguments.putInt(AccessibilityNodeInfo.ACTION_ARGUMENT_MOVEMENT_GRANULARITY_INT, AccessibilityNodeInfo
                    .MOVEMENT_GRANULARITY_LINE);
            arguments.putBoolean(AccessibilityNodeInfo.ACTION_ARGUMENT_EXTEND_SELECTION_BOOLEAN, true);
            mAccessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_PREVIOUS_AT_MOVEMENT_GRANULARITY,
                    arguments);
            //粘贴内容
            ClipData clipData = ClipData.newPlainText(context.getPackageName(), text);
            ClipboardManager clipboardManager = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
            clipboardManager.setPrimaryClip(clipData);
            mAccessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_PASTE);
        } catch (Exception e) {
            throw new MyException(e);
        }
    }

    public void scrollForward() throws MyException {
        try {
            mAccessibilityNodeInfo.performAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);
        } catch (Exception e) {
            throw new MyException(e);
        }
    }

    public void getBoundsInScreen(Rect bounds) throws MyException {
        try {
            mAccessibilityNodeInfo.getBoundsInScreen(bounds);
        } catch (Exception e) {
            throw new MyException(e);
        }
    }
}