public class ArgonConst {

    // PROTOCOL NAMES
    public static final String ARGON = "argon";
    public static final String ARGON_XQ = "argonquery";
    public static final String ARGON_REPO = "argonrepo";

    // DATABASE NAMES
    public static final String ARGON_DB = "~argon";

    public static final String BACKUP_DB_BASE = "~history_";

    public static final String BACKUP_RESTXQ_BASE = "~history_~restxq/";
    public static final String BACKUP_REPO_BASE = "~history_~repo/";

    public static final String META_DB_BASE = "~meta_";
    public static final String META_RESTXQ_BASE = "~meta_~restxq/";
    public static final String META_REPO_BASE = "~meta_~repo/";

    public static final String DATE_FORMAT = "yyyy-MM-dd_HH-mm";

    // RESOURCE NAMES
    public static final String META_TEMPLATE = "MetaTemplate.xml";
    public static final String LOCK_FILE = "~usermanagement";
    public static final String EMPTY_FILE = ".empty.xml";

    public static final String BXERR_PERMISSION = "BASX0001";
} public final class BaseXResource {
    /**
     * Entry name.
     */
    public final String name;
    /**
     * Entry type.
     */
    public final BaseXType type;
    /**
     * Source.
     */
    public final BaseXSource source;

    /**
     * Constructor.
     *
     * @param name   name
     * @param type   type
     * @param source source
     */
    public BaseXResource(final String name, final BaseXType type, final BaseXSource source) {
        this.name = name;
        this.type = type;
        this.source = source;
    }

    public String getName() {
        return name;
    }

    public BaseXType getType() {
        return type;
    }

    @Override
    public String toString() {
        return name + " (" + type + ")";
    }

    public String getURLString() {
        return source.getProtocol() + ":" + name;
    }
} public enum BaseXSource {

    /**
     * Database.
     */
    DATABASE("argon"),
//    /**
//     * RESTXQ.
//     */
//    RESTXQ("argonquery"),
    /**
     * Repository.
     */
    REPO("argonrepo");

    private final String protocol;

    BaseXSource(String protocol) {

        this.protocol = protocol;
    }

    public String getProtocol() {
        return protocol;
    }

    /**
     * Returns a source.
     *
     * @param string string representation
     * @return enumeration
     */
    public static BaseXSource get(final String string) {
        return BaseXSource.valueOf(string.toUpperCase(Locale.ENGLISH));
    }

    @Override
    public String toString() {
        return name().toLowerCase(Locale.ENGLISH);
    }
} public class TreeListener extends MouseAdapter implements TreeSelectionListener, TreeWillExpandListener,
        KeyListener, ObserverInterface<MsgTopic> {

    private static final Logger logger = LogManager.getLogger(TreeListener.class);
    private static final PluginWorkspace workspace = PluginWorkspaceProvider.getPluginWorkspace();

    private final ArgonTree tree;
    private final DefaultTreeModel treeModel;
    private TreePath path;
    private TreeNode node;
    private boolean showErrorMessages = true;
    private boolean newExpandEvent;
    private boolean singleClick = true;
    private boolean doubleClickExpandEnabled = true;
    private Timer timer;
    private final ArgonPopupMenu contextMenu;

    public TreeListener(ArgonTree tree, TreeModel treeModel, ArgonPopupMenu contextMenu) {
        this.tree = tree;
        this.treeModel = (DefaultTreeModel) treeModel;
        this.newExpandEvent = true;
        this.contextMenu = contextMenu;
        final ActionListener actionListener = e -> {
            timer.stop();
            if (singleClick) {
                singleClickHandler(e);
            } else {
                try {
                    doubleClickHandler(e);
                } catch (ParseException ex) {
                    logger.error(ex);
                }
            }
        };
        final int doubleClickDelay = 300;
        timer = new javax.swing.Timer(doubleClickDelay, actionListener);
        timer.setRepeats(false);
    }

    public void setShowErrorMessages(boolean show) {
        showErrorMessages = show;
    }

    /*
     * methods of MouseAdapter
     */

    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 1) {
            singleClick = true;
            timer.start();
        } else {
            singleClick = false;
        }
    }


    private static boolean isRightClick(MouseEvent e) {
        return (e.getButton()==MouseEvent.BUTTON3 ||
                (System.getProperty("os.name").contains("Mac OS") &&
                        (e.getModifiers() & InputEvent.BUTTON1_MASK) != 0 &&
                        (e.getModifiers() & InputEvent.CTRL_MASK) != 0));
    }


    @Override
    public void mousePressed(MouseEvent e) {
        path = tree.getPathForLocation(e.getX(), e.getY());
        try {
            if (path != null) {
                node = (TreeNode) path.getLastPathComponent();
            }
        } catch (NullPointerException er) {
            er.printStackTrace();
        }
        if (e.isPopupTrigger()) {
            contextMenu.show(e.getComponent(), e.getX(), e.getY(), path);
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        path = tree.getPathForLocation(e.getX(), e.getY());
        try {
            if (path != null) {
                node = (TreeNode) path.getLastPathComponent();
            }
        } catch (NullPointerException er) {
            er.printStackTrace();
        }
       // if (e.isPopupTrigger()) {
        if (isRightClick(e)) {
            contextMenu.show(e.getComponent(), e.getX(), e.getY(), path);
        }
    }


    /*
     * methods of interface TreeSelectionListener
     */

    @Override
    public void valueChanged(TreeSelectionEvent e) {
        path = e.getNewLeadSelectionPath();
        node = (TreeNode) tree.getLastSelectedPathComponent();
    }


    /*
     * methods of interface TreeWillExpandListener
     */

    @Override
    public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {
        // method is called twice, if new data is loaded--prevent database check in 2nd call
        final boolean newTreeExpandEvent = this.newExpandEvent;
        path = event.getPath();
        node = (TreeNode) path.getLastPathComponent();
        int depth = path.getPathCount();
        if (depth > 1 && node.getAllowsChildren() && this.newExpandEvent) {
            final BaseXSource source = TreeUtils.sourceFromTreePath(path);
            String db_path;
            if (depth > 2) {    // get path in source
                db_path = (((String) ((ArgonTreeNode) node).getTag()).split(":/*"))[1] + "/";
            } else {
                db_path = "";
            }

            List<BaseXResource> childList;
            try {
                childList = ConnectionWrapper.list(source, db_path);
            } catch (Exception er) {
                childList = new ArrayList<>();
                logger.debug(er);
                String error = er.getMessage();
                if (error == null || error.equals("")) {
                    error = "Database connection could not be established.";
                }
                if (showErrorMessages) {
                    workspace.showInformationMessage(Lang.get(Lang.Keys.warn_failedlist) + "\n" + error);
                }
            }

            if (updateExpandedNode((MutableTreeNode) node, childList)) {
                this.newExpandEvent = false;
                tree.expandPath(path);
            }

        }
        if (!newTreeExpandEvent) {
            this.newExpandEvent = true;
        }
    }

    @Override
    public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
    }


    /*
     * methods for MouseAdapter
     */

    private void singleClickHandler(ActionEvent e) {
        logger.debug("-- single click --");
    }

    private void doubleClickHandler(ActionEvent e) throws ParseException {
        logger.debug("-- double click --");
        TreePath[] paths = tree.getSelectionPaths();
        if (paths != null) {
            for (TreePath path : paths) {
                if (((TreeNode) path.getLastPathComponent()).getAllowsChildren()) {
                    if (doubleClickExpandEnabled) {
                        try {
                            treeWillExpand(new TreeExpansionEvent(this, path));
                        } catch (ExpandVetoException eve) {
                            logger.debug("Expand Veto: ", eve.getMessage());
                        }
                    }
                } else {
                    doubleClickAction(path);
                }
            }
        }
    }

    // made public for access with AspectJ
    @SuppressWarnings("all")
    public static void doubleClickAction(TreePath path) {
        //String db_path = ((ArgonTreeNode) path.getLastPathComponent()).getTag();
        final String dbPath = TreeUtils.urlStringFromTreePath(path);
        WorkspaceUtils.openURLString(dbPath);
    }

    /*
     * method for interface Observer
     */

    @Override
    public void update(MsgTopic type, Object... message) {
        // is notified as observer when changes have been made to the database file structure
        // updates the tree if necessary
        TreeNode currNode;
        TreePath currPath;

        logger.info("Tree needs to update: " + message[0]);

        if (type instanceof SaveFileEvent || type instanceof NewDirEvent) {
            String[] protocol = ((String) message[0]).split(":/*");
            String[] path = protocol[1].split("/");
            currPath = new TreePath(treeModel.getRoot());
            switch (protocol[0]) {
//                case ArgonConst.ARGON_REPO:
//                    currPath = TreeUtils.pathByAddingChildAsStr(currPath, Lang.get(Lang.Keys.tree_repo));
//                    break;
//                case ArgonConst.ARGON_XQ:
//                    currPath = TreeUtils.pathByAddingChildAsStr(currPath, Lang.get(Lang.Keys.tree_restxq));
//                    break;
                default:
                    currPath = TreeUtils.pathByAddingChildAsStr(currPath, Lang.get(Lang.Keys.tree_DB));
            }
            currNode = (TreeNode) currPath.getLastPathComponent();
            boolean expanded = false;
            Boolean isFile;
            for (int i = 0; i < path.length; i++) {
                if (tree.isExpanded(currPath)) expanded = true;
                if (expanded || (i == path.length - 1)) { // update tree now only if file is in visible path
                    if (TreeUtils.isNodeAsStrChild(currNode, path[i]) == -1) {
                        isFile = (i + 1 == path.length) && type instanceof SaveFileEvent;
                        TreeUtils.insertStrAsNodeLexi(treeModel, path[i], (DefaultMutableTreeNode) currNode, isFile);
                        treeModel.reload(currNode);
                    }
                    currPath = TreeUtils.pathByAddingChildAsStr(currPath, path[i]);
                    currNode = (DefaultMutableTreeNode) currPath.getLastPathComponent();
                } else {
                    break;
                }
            }
        }
    }

    /*
     * other methods
     */

    public void setDoubleClickExpand(boolean expand) {
        doubleClickExpandEnabled = expand;
    }

    private boolean updateExpandedNode(MutableTreeNode node, List<BaseXResource> newChildrenList) {
        final Set<String> childrenValues = newChildrenList.stream()
                .map(child -> child.name)
                .collect(Collectors.toSet());

        DefaultMutableTreeNode newChild;
        final List<String> oldChildren = new ArrayList<>();
        String oldChild;
        boolean treeChanged = false;

        // check whether old children are in new list and vice versa
        if (node.getChildCount() > 0) {
            boolean[] inNewList = new boolean[node.getChildCount()];
            if (newChildrenList.size() > 0) {
                for (int i = 0; i < node.getChildCount(); i++) {
                    final DefaultMutableTreeNode currNode = (DefaultMutableTreeNode) node.getChildAt(i);
                    oldChild = currNode.getUserObject().toString();
                    oldChildren.add(oldChild);
                    if (childrenValues.contains(oldChild)) {
                        inNewList[i] = true;
                    }
                }
            }
            for (int i = node.getChildCount() - 1; i > -1; i--) {
                if (!inNewList[i]) {
                    treeModel.removeNodeFromParent((MutableTreeNode) node.getChildAt(i));
                    treeModel.nodeChanged(node);
                    treeChanged = true;
                }
            }
        }
        if (node.getChildCount() == 0) {  // if old list was empty skip lexicographic insert (faster)
            for (BaseXResource newPossibleChild : newChildrenList) {
                final String url = ((ArgonTreeNode) node).getTag().toString() + "/" + newPossibleChild.name;
                newChild = ClassFactory.getInstance().getTreeNode(newPossibleChild.name, url);
                newChild.setAllowsChildren(newPossibleChild.type == BaseXType.DIRECTORY);
                treeModel.insertNodeInto(newChild, node, node.getChildCount());
                treeChanged = true;
            }
        } else {
            for (BaseXResource newPossibleChild : newChildrenList) {
                if (!oldChildren.contains(newPossibleChild.name)) {
                    TreeUtils.insertStrAsNodeLexi(treeModel, newPossibleChild.name, (DefaultMutableTreeNode) node,
                            newPossibleChild.type != BaseXType.DIRECTORY);
                    treeChanged = true;
                }
            }
        }
        return treeChanged;
    }

    public TreePath getPath() {
        return this.path;
    }

    public TreeNode getNode() {
        return this.node;
    }

    /*
     * methods for interface KeyListener
     */

    @Override
    public void keyTyped(KeyEvent e) {
    }

    @Override
    public void keyPressed(KeyEvent e) {
        int key = e.getKeyCode();
        switch (key) {
            case KeyEvent.VK_DELETE:
                new DeleteAction(tree).actionPerformed(null);
                break;
            case KeyEvent.VK_F5:
                new RefreshTreeAction(tree).actionPerformed(null);
                break;
            case KeyEvent.VK_ENTER:
                try {
                    doubleClickHandler(null);
                } catch (ParseException pe) {
                    // if URL raises exc    eption, just ignore
                }
                break;
            case KeyEvent.VK_INSERT:
                if (TreeUtils.isDir(path) || TreeUtils.isDB(path) || TreeUtils.isFileSource(path)) {
                    new AddNewFileAction(tree).actionPerformed(null);
                    break;
                }
                if (TreeUtils.isDbSource(path)) {
                    new AddDatabaseAction().actionPerformed(null);
                    break;
                }
                break;
            default:
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
    }
} public class TreeUtils {

    private static final Logger logger = LogManager.getLogger(TreeUtils.class);

    static final int DEPTH_ROOT = 1;
    static final int DEPTH_SOURCE = 2;
    static final int DEPTH_DB = 3;

    private static TreeModel model;

    public static void init(TreeModel treeModel) {
        model = treeModel;
    }

    public static void insertStrAsNodeLexi(TreeModel treeModel, String child, DefaultMutableTreeNode parent, Boolean childIsFile) {
        final DefaultMutableTreeNode childNode = newChild(child, parent, childIsFile);
        boolean inserted = false;
        for (int i = 0; i < parent.getChildCount(); i++) {
            final DefaultMutableTreeNode currNode = (DefaultMutableTreeNode) parent.getChildAt(i);
            final Boolean nextIsFile = !currNode.getAllowsChildren();
            if (((currNode.getUserObject().toString().compareTo(child) > 0) && (nextIsFile.compareTo(childIsFile) == 0)) ||
                    (nextIsFile.compareTo(childIsFile) > 0)) {    // dirs before files
                ((DefaultTreeModel) treeModel).insertNodeInto(childNode, parent, i);
                inserted = true;
                break;
            }
        }
        if (!inserted) {
            ((DefaultTreeModel) treeModel).insertNodeInto(childNode, parent, parent.getChildCount());
        }
    }

    public static DefaultMutableTreeNode insertStrAsNodeLexi(String child, DefaultMutableTreeNode parent, Boolean childIsFile) {
        final DefaultMutableTreeNode childNode = newChild(child, parent, childIsFile);
        boolean inserted = false;
        for (int i = 0; i < parent.getChildCount(); i++) {
            final DefaultMutableTreeNode currNode = (DefaultMutableTreeNode) parent.getChildAt(i);
            final AtomicReference<Boolean> nextIsFile = new AtomicReference<>();
            nextIsFile.set(!currNode.getAllowsChildren());
            if (((currNode.getUserObject().toString().compareTo(child) > 0) && (nextIsFile.get().compareTo(childIsFile) == 0)) ||
                    (nextIsFile.get().compareTo(childIsFile) > 0)) {    // dirs before files
                parent.insert(childNode, i);
                inserted = true;
                break;
            }
        }
        if (!inserted) {
            parent.insert(childNode, parent.getChildCount());
        }
        return childNode;
    }

    private static DefaultMutableTreeNode newChild(String child, DefaultMutableTreeNode parent, Boolean childIsFile) {
        final String delim = (parent.getLevel() < DEPTH_SOURCE) ? "" : "/";
        final DefaultMutableTreeNode childNode = ClassFactory.getInstance().getTreeNode(child,
                ((ArgonTreeNode) parent).getTag().toString() + delim + child);
        if (childIsFile) {
            childNode.setAllowsChildren(false);
        } else {
            childNode.setAllowsChildren(true);
        }
        return childNode;
    }

    public static int isNodeAsStrChild(TreeNode parent, String child) {
        for (int i = 0; i < parent.getChildCount(); i++) {
            if (((DefaultMutableTreeNode) parent.getChildAt(i)).getUserObject().toString().equals(child)) {
                return i;
            }
        }
        return -DEPTH_ROOT;
    }

    public static TreePath pathByAddingChildAsStr(TreePath currPath, String child) {
        // returns TreePath to child given by String, if child doesn't exist returns null!
        final DefaultMutableTreeNode currNode = (DefaultMutableTreeNode) currPath.getLastPathComponent();
        int childNodeIndex = isNodeAsStrChild(currNode, child);
        if (childNodeIndex != -DEPTH_ROOT) {
            return new TreePath(((DefaultMutableTreeNode) currNode.getChildAt(childNodeIndex)).getPath());
        }
        return null;
    }

    public static TreePath pathFromURLString(String urlString) {
        TreePath path = new TreePath(model.getRoot());
        final BaseXSource source = CustomProtocolURLUtils.sourceFromURLString(urlString);
        switch (source) {
//            case REPO:
//                path = pathByAddingChildAsStr(path, Lang.get(Lang.Keys.tree_repo));
//                break;
//            case RESTXQ:
//                path = pathByAddingChildAsStr(path, Lang.get(Lang.Keys.tree_restxq));
//                break;
            default:
                path = pathByAddingChildAsStr(path, Lang.get(Lang.Keys.tree_DB));
        }
        final String[] protocolResource = urlString.split(":/*");
        if (protocolResource.length > DEPTH_ROOT) {
            String[] pathParts = protocolResource[DEPTH_ROOT].split("/");
            for (String res : pathParts) {
                path = pathByAddingChildAsStr(path, res);
            }
        }
        return path;
    }

    public static BaseXSource sourceFromTreePath(TreePath path) {
        if (path.getPathCount() > DEPTH_ROOT) {
            final String sourceStr = path.getPathComponent(DEPTH_ROOT).toString();
            if (sourceStr.equals(Lang.get(Lang.Keys.tree_DB))) {
                return BaseXSource.DATABASE;
            }
//            if (sourceStr.equals(Lang.get(Lang.Keys.tree_restxq)))
//                return BaseXSource.RESTXQ;
            if (sourceStr.equals(Lang.get(Lang.Keys.tree_repo))) {
                return BaseXSource.REPO;
            }
            return null;
        } else {
            return null;
        }
    }

    public static String protocolFromTreePath(TreePath path) {
        if (path.getPathCount() > DEPTH_ROOT) {
            final String sourceStr = path.getPathComponent(DEPTH_ROOT).toString();
            if (sourceStr.equals(Lang.get(Lang.Keys.tree_DB))) {
                return ArgonConst.ARGON;
            }
//            if (sourceStr.equals(Lang.get(Lang.Keys.tree_restxq)))
//                return ArgonConst.ARGON_XQ;
            if (sourceStr.equals(Lang.get(Lang.Keys.tree_repo))) {
                return ArgonConst.ARGON_REPO;
            }
            return null;
        } else {
            return null;
        }
    }

    public static String resourceFromTreePath(TreePath path) {
        final StringBuilder resource = new StringBuilder();
        if (path.getPathCount() > DEPTH_ROOT) {
            for (int i = DEPTH_SOURCE; i < path.getPathCount(); i++) {
                if (i > DEPTH_SOURCE) {
                    resource.append('/');
                }
                resource.append(path.getPathComponent(i).toString());
            }
        }
        return resource.toString();
    }

    public static String urlStringFromTreePath(TreePath path) {
        final StringBuilder db_path;
//        if (path.getPathComponent(1).toString().equals(Lang.get(Lang.Keys.tree_restxq)))
//            db_path = new StringBuilder(ArgonConst.ARGON_XQ + ":");
//        else
//        if (path.getPathComponent(1).toString().equals(Lang.get(Lang.Keys.tree_repo)))
//            db_path = new StringBuilder(ArgonConst.ARGON_REPO + ":");
//        else
            db_path = new StringBuilder(ArgonConst.ARGON + ":");
        for (int i = DEPTH_SOURCE; i < path.getPathCount(); i++) {
            if (i > DEPTH_SOURCE) {
                db_path.append('/');
            }
            db_path.append(path.getPathComponent(i).toString());
        }
        return db_path.toString();
    }

    public static String treeStringFromTreePath(TreePath path) {
        final StringBuilder db_path = new StringBuilder(Lang.get(Lang.Keys.tree_root));
        for (int i = DEPTH_ROOT; i < path.getPathCount(); i++) {
            db_path.append("/").append(path.getPathComponent(i).toString());
        }
        return db_path.toString();
    }

    public static String urlStringFromTreeString(String treeString) {
        final String[] components = treeString.split("/");
        final StringBuilder db_path;

        if (components.length > DEPTH_SOURCE) {
//            if (components[1].equals(Lang.get(Lang.Keys.tree_restxq)))
//                db_path = new StringBuilder(ArgonConst.ARGON_XQ + ":");
//            else
//            if (components[1].equals(Lang.get(Lang.Keys.tree_repo)))
//                db_path = new StringBuilder(ArgonConst.ARGON_REPO + ":");
//            else
                db_path = new StringBuilder(ArgonConst.ARGON + ":");
            db_path.append(treeString.substring(components[0].length() + components[DEPTH_ROOT].length() + DEPTH_SOURCE));
        } else {
            db_path = new StringBuilder("");
        }
        return db_path.toString();
    }

    public static String fileStringFromPathString(String path) {
        if (path.equals("") || path.endsWith("/") || path.endsWith("\\")) {
            return "";
        } else {
            String[] nodes = path.split("\\\\|/");
            return nodes[nodes.length - DEPTH_ROOT];
        }
    }

    public static TreePath pathToDepth(TreePath path, int depth) {
        TreePath returnPath = path;
        if (path.getPathCount() < depth) {
            return new TreePath(new Object[0]);
        } else {
            for (int i = path.getPathCount(); i > (depth + DEPTH_ROOT); i--) {
                returnPath = returnPath.getParentPath();
            }
        }
        return returnPath;
    }

    public static boolean isFile(TreePath path) {
//        logger.info("isFile " + path);
        final DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
        return (!node.getAllowsChildren());
    }

    public static boolean isDir(TreePath path) {
//        logger.info("isDir " + path);
        final DefaultMutableTreeNode clickedNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        final int pathCount = path.getPathCount();
        return (clickedNode.getAllowsChildren() &&
                (((pathCount > DEPTH_DB) &&
                        (path.getPathComponent(DEPTH_ROOT).toString().equals(Lang.get(Lang.Keys.tree_DB)))) ||
                        ((pathCount > DEPTH_SOURCE) &&
                                (!path.getPathComponent(DEPTH_ROOT).toString().equals(Lang.get(Lang.Keys.tree_DB))))));
    }

    public static boolean isDB(TreePath path) {
//        logger.info("isDB " + path);
        final int pathCount = path.getPathCount();
        return (pathCount == DEPTH_DB) &&
                (path.getPathComponent(DEPTH_ROOT).toString().equals(Lang.get(Lang.Keys.tree_DB)));
    }

    public static boolean isInDB(TreePath path) {
//        logger.info("isInDB " + path);
        final int pathCount = path.getPathCount();
        return (pathCount > DEPTH_DB) &&
                (path.getPathComponent(DEPTH_ROOT).toString().equals(Lang.get(Lang.Keys.tree_DB)));
    }

//    public static boolean isInRestXQ(TreePath path) {
//        int pathCount = path.getPathCount();
//        return (pathCount > 2) &&
//                (path.getPathComponent(1).toString().equals(Lang.get(Lang.Keys.tree_restxq)));
//    }

//    public static boolean isInRepo(TreePath path) {
//        int pathCount = path.getPathCount();
//        return (pathCount > 2) &&
//                (path.getPathComponent(1).toString().equals(Lang.get(Lang.Keys.tree_repo)));
//    }

    public static boolean isSource(TreePath path) {
//        logger.info("isSource " + path);
        final int pathCount = path.getPathCount();
        return (pathCount == DEPTH_SOURCE);
    }

    public static boolean isRoot(TreePath path) {
//        logger.info("isRoot " + path);
        final int pathCount = path.getPathCount();
        return (pathCount == DEPTH_ROOT);
    }

    public static boolean isDbSource(TreePath path) {
//        logger.info("isDBSource " + path);
        final int pathCount = path.getPathCount();
        return ((pathCount == DEPTH_SOURCE) && path.getPathComponent(DEPTH_ROOT).toString().equals(Lang.get(Lang.Keys.tree_DB)));
    }

    public static boolean isFileSource(TreePath path) {
//        logger.info("isFileSource " + path);
        return (TreeUtils.isSource(path) && !path.getPathComponent(DEPTH_ROOT).toString().equals(Lang.get(Lang.Keys.tree_DB)));
    }

    public static boolean isWEBINF(TreePath path) {
        final DefaultMutableTreeNode clickedNode = (DefaultMutableTreeNode) path.getLastPathComponent();
        final int pathCount = path.getPathCount();
        return TreeUtils.isDir(path)
                && clickedNode.getUserObject().toString().equals("WEB-INF")
                && (
//                    ((pathCount == DEPTH_DB) && path.getPathComponent(1).toString().equals(Lang.get(Lang.Keys.tree_restxq))) ||
                ((pathCount == 5) && path.getPathComponent(DEPTH_ROOT).toString().equals(Lang.get(Lang.Keys.tree_DB)))
                );
    }

}
 public final class ConnectionWrapper {

    private static final Logger logger = LogManager.getLogger(ConnectionWrapper.class);

    private ConnectionWrapper() {
    }

    public static void init() {
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            connection.init();
        } catch (IOException | NullPointerException ex) {
            logger.debug("Argon initialization failed!");
        }
    }

    public static void create(String db) throws IOException {
        String chop = ArgonOptionPage.getOption(ArgonOptionPage.KEY_BASEX_DB_CREATE_CHOP, false).toLowerCase();
        String ftindex = ArgonOptionPage.getOption(ArgonOptionPage.KEY_BASEX_DB_CREATE_FTINDEX, false).toLowerCase();
        String textindex = ArgonOptionPage.getOption(ArgonOptionPage.KEY_BASEX_DB_CREATE_TEXTINDEX, false).toLowerCase();
        String attrindex = ArgonOptionPage.getOption(ArgonOptionPage.KEY_BASEX_DB_CREATE_ATTRINDEX, false).toLowerCase();
        String tokenindex = ArgonOptionPage.getOption(ArgonOptionPage.KEY_BASEX_DB_CREATE_TOKENINDEX, false).toLowerCase();
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            connection.create(db, chop, ftindex, textindex, attrindex, tokenindex);
            TopicHolder.newDir.postMessage(ArgonConst.ARGON + ":" + db);
        } catch (NullPointerException ex) {
            String error = ex.getMessage();
            if ((error == null) || error.equals("null"))
                throw new IOException("Database connection could not be established.");
        }
    }

    public static void save(URL url, byte[] bytes) throws IOException {
        try (ByteArrayOutputStream os = new BaseXByteArrayOutputStream(url, "UTF-8")) {
            os.write(bytes);
        } catch (NullPointerException npe) {
            logger.info("Error saving to " + url.toString() + ": no database connection");
            throw new NoDatabaseConnectionException();
        } catch (IOException ioe) {
            logger.error("IO error saving to " + url.toString() + ": ", ioe.getMessage());
            throw new IOException(ioe);
        }
    }

    public static void save(URL url, byte[] bytes, String encoding, boolean versionUp) throws IOException {
        try (ByteArrayOutputStream os = new BaseXByteArrayOutputStream(url, encoding, versionUp)) {
            os.write(bytes);
        } catch (NullPointerException npe) {
            logger.info("Error saving to " + url.toString() + ": no database connection");
            throw new NoDatabaseConnectionException();
        } catch (IOException ioe) {
            logger.error("IO error saving to " + url.toString() + ": ", ioe.getMessage());
            throw new IOException(ioe);
        }
    }

    public static void save(URL url, byte[] bytes, String encoding) throws IOException {
        try (ByteArrayOutputStream os = new BaseXByteArrayOutputStream(url, encoding)) {
            os.write(bytes);
        } catch (NullPointerException npe) {
            logger.info("Error saving to " + url.toString() + ": no database connection");
            throw new NoDatabaseConnectionException();
        } catch (IOException ioe) {
            logger.error("IO error saving to " + url.toString() + ": ", ioe.getMessage());
            throw new IOException(ioe);
        }
    }

    public static void save(String owner, URL url, byte[] bytes, String encoding) throws IOException {
        try (ByteArrayOutputStream os = new BaseXByteArrayOutputStream(owner, url, encoding)) {
            os.write(bytes);
        } catch (NullPointerException npe) {
            logger.info("Error saving to " + url.toString() + ": no database connection");
            throw new NoDatabaseConnectionException();
        } catch (IOException ioe) {
            logger.error("IO error saving to " + url.toString() + ": ", ioe.getMessage());
            throw new IOException(ioe);
        }
    }

    public static void save(String owner, boolean binary, URL url, byte[] bytes) throws IOException {
        try (ByteArrayOutputStream os = new BaseXByteArrayOutputStream(owner, binary, url)) {
            os.write(bytes);
        } catch (NullPointerException npe) {
            logger.info("Error saving to " + url.toString() + ": no database connection");
            throw new NoDatabaseConnectionException();
        } catch (IOException ioe) {
            logger.error("IO error saving to " + url.toString() + ": ", ioe.getMessage());
            throw new IOException(ioe);
        }
    }

    public static void save(boolean binary, URL url, byte[] bytes) throws IOException {
        try (ByteArrayOutputStream os = new BaseXByteArrayOutputStream(binary, url)) {
            os.write(bytes);
        } catch (NullPointerException npe) {
            logger.info("Error saving to " + url.toString() + ": no database connection");
            throw new NoDatabaseConnectionException();
        } catch (IOException ioe) {
            logger.error("IO error saving to " + url.toString() + ": ", ioe.getMessage());
            throw new IOException(ioe);
        }
    }

    public static void save(boolean binary, URL url, byte[] bytes, boolean versionUp) throws IOException {
        try (ByteArrayOutputStream os = new BaseXByteArrayOutputStream(binary, url, versionUp)) {
            os.write(bytes);
        } catch (NullPointerException npe) {
            logger.info("Error saving to " + url.toString() + ": no database connection");
            throw new NoDatabaseConnectionException();
        } catch (IOException ioe) {
            logger.error("IO error saving to " + url.toString() + ": ", ioe.getMessage());
            throw new IOException(ioe);
        }
    }

    public static InputStream getInputStream(URL url) throws IOException {
        ByteArrayInputStream inputStream;
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            logger.info("Requested new InputStream: " + url.toString());
            inputStream = new ByteArrayInputStream(connection.get(CustomProtocolURLUtils.sourceFromURL(url),
                    CustomProtocolURLUtils.pathFromURL(url), false));
        } catch (NullPointerException npe) {
            logger.info("Error obtaining input stream from " + url.toString() + ": no database connection");
            throw new NoDatabaseConnectionException();
        } catch (IOException io) {
            logger.debug("Failed to obtain InputStream: ", io.getMessage());
            throw new IOException(io);
        }
        return inputStream;
    }

    public static List<BaseXResource> list(BaseXSource source, String path) throws IOException {
        logger.info("list " + source + " "+ path);
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            return connection.list(source, path);
        } catch (NullPointerException npe) {
            final PrintWriter buf = new PrintWriter(new StringWriter());
            npe.printStackTrace(buf);
            logger.info("Error listing path " + path + ": no database connection : " + buf.toString());
            throw new NoDatabaseConnectionException();
        }
    }

    /**
     * lists all resources in the path, including directories
     *
     * @param source source in which path resides
     * @param path   path to list
     * @return list of all resources in path, entries contain full path as name, for databases without the database name
     * @throws IOException throws exception if connection returns an exception/error code
     */
    public static List<BaseXResource> listAll(BaseXSource source, String path) throws IOException {
        logger.info("listAll" + source + " "+ path);
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            return connection.listAll(source, path);
        } catch (NullPointerException npe) {
            logger.info("Error listing path " + path + ": no database connection");
            throw new NoDatabaseConnectionException();
        }
    }

    public static boolean directoryExists(BaseXSource source, String path) {
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            List<BaseXResource> resourceList = connection.list(source, path);
            return (resourceList.size() != 0);
        } catch (NullPointerException npe) {
            logger.info("Error checking for directory " + path + ": no database connection");
            return true;
        } catch (IOException ioe) {
            return false;
        }
    }

    public static boolean isLocked(BaseXSource source, String path) {
        boolean isLocked = false;
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            if (connection.locked(source, path))
                isLocked = true;
        } catch (Throwable ie) {
            isLocked = true;
            logger.debug("Querying LOCKED returned: ", ie.getMessage());
        }
        return isLocked;
    }

    public static boolean isLockedByUser(BaseXSource source, String path) {
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            return connection.lockedByUser(source, path);
        } catch (Throwable ioe) {
            logger.debug(ioe);
        }
        return false;
    }

    public static void lock(BaseXSource source, String path) {
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            connection.lock(source, path);
        } catch (Throwable ioe) {
            logger.error("Failed to lock resource " + path + " in " + source.toString() + ": " + ioe.getMessage());
        }
    }

    public static void unlock(BaseXSource source, String path) {
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            connection.unlock(source, path);
        } catch (Throwable ioe) {
            logger.error("Failed to unlock resource " + path + " in " + source.toString() + ": " + ioe.getMessage());
        }
    }

    public static List<String> findFiles(BaseXSource source, String path, String filter, boolean caseSensitive) throws IOException {
        List<String> result;
        StringBuilder regEx = new StringBuilder(caseSensitive ? "" : "(?i)");
        for (int i = 0; i < filter.length(); i++) {
            char c = filter.charAt(i);
            switch (c) {
                case '*':
                    regEx.append(".*");
                    break;
                case '?':
                    regEx.append('.');
                    break;
                case '.':
                    regEx.append("\\.");
                    break;
                default:
                    regEx.append(c);
            }
        }
        String regExString = regEx.toString();
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            result = connection.search(source, path, regExString);
            for (int i = result.size() - 1; i > -1; i--) {
                String foundPath = result.get(i);
                String foundFile = TreeUtils.fileStringFromPathString(foundPath);
                Matcher matcher = Pattern.compile(regExString).matcher(foundFile);
                if (!matcher.find())
                    result.remove(foundPath);
            }
        } catch (NullPointerException npe) {
            logger.error("Error searching for files: no database connection");
            throw new NoDatabaseConnectionException();
        }
        return result;
    }

    public static List<String> parse(String path) throws IOException {
        List<String> result = new ArrayList<>();
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            connection.parse(path);
        } catch (BaseXQueryException ex) {
            result.add(Integer.toString(ex.getLine()));
            result.add(Integer.toString(ex.getColumn()));
            result.add(ex.getInfo());
        }
        return result;
    }

    public static String query(String query, String[] parameter) throws IOException {
        return "<response>\n" + sendQuery(query, parameter) + "\n</response>";
    }

    private static String sendQuery(String query, String[] parameter) throws IOException {
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            return connection.xquery(query, parameter);
        } catch (NullPointerException npe) {
            logger.info("Error sending query: no database connection");
            throw new NoDatabaseConnectionException();
        }
    }

    private static List<String> searchInFiles(String query, String path, String filter, boolean wholeMatch, boolean exactCase)
            throws IOException {
        String[] parameter = {"PATH", path, "FILTER", filter, "WHOLE", Boolean.toString(wholeMatch),
                "EXACTCASE", Boolean.toString(exactCase)};
        String result = sendQuery(query, parameter);
        String db_name = (path.split("/"))[0];
        final ArrayList<String> list = new ArrayList<>();
        if (!result.isEmpty()) {
            final String[] results = result.split("\r?\n");
            for (String res : results) {
                list.add("argon:" + db_name + "/" + res);
            }
        }
        return list;
    }

    public static List<String> searchAttributes(String path, String filter, boolean wholeMatch, boolean exactCase)
            throws IOException {
        return searchInFiles(ConnectionUtils.getQuery("search-attributes"), path, filter, wholeMatch, exactCase);
    }

    public static List<String> searchAttributeValues(String path, String filter, boolean wholeMatch, boolean exactCase)
            throws IOException {
        return searchInFiles(ConnectionUtils.getQuery("search-attrvalues"), path, filter, wholeMatch, exactCase);
    }

    public static List<String> searchElements(String path, String filter, boolean wholeMatch, boolean exactCase)
            throws IOException {
        return searchInFiles(ConnectionUtils.getQuery("search-elements"), path, filter, wholeMatch, exactCase);
    }

    public static List<String> searchText(String path, String filter, boolean wholeMatch, boolean exactCase)
            throws IOException {
        return searchInFiles(ConnectionUtils.getQuery("search-text"), path, filter, wholeMatch, exactCase);
    }

    public static boolean resourceExists(BaseXSource source, String resource) {
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            return connection.exists(source, resource);
        } catch (Throwable ioe) {
            logger.error("Failed to ask BaseX for existence of resource " + resource + ": " + ioe.getMessage());
            return false;
        }
    }

    public static boolean pathContainsLockedResource(BaseXSource source, String path) {
        byte[] lockFile;
        try (Connection connection = BaseXConnectionWrapper.getConnection()) {
            lockFile = connection.get(BaseXSource.DATABASE, ArgonConst.ARGON_DB + "/" + ArgonConst.LOCK_FILE, false);
            Document dom = XMLUtils.docFromByteArray(lockFile);
            XPathExpression expression = XMLUtils.getXPathExpression("*//" + source.toString());
            NodeList lockedResources = (NodeList) expression.evaluate(dom, XPathConstants.NODESET);
            String[] pathComponents = path.split("/");
            for (int i = 0; i < lockedResources.getLength(); i++) {
                String[] resourceComponents = lockedResources.item(i).getTextContent().split("/");
                if (resourceComponents.length >= pathComponents.length) {
                    boolean isEqual = true;
                    for (int k = 0; k < pathComponents.length; k++) {
                        if (!pathComponents[k].equals(resourceComponents[k]))
                            isEqual = false;
                    }
                    if (isEqual)
                        return true;
                }
            }
        } catch (IOException ioe) {
            logger.error("Failed to obtain lock list: " + ioe.getMessage());
            return true;
        } catch (ParserConfigurationException | SAXException | XPathExpressionException xe) {
            logger.error("Failed to parse lock file XML: " + xe.getMessage());
            return true;
        } catch (Throwable t) {
            return true;
        }
        return false;
    }

    /**
     * Adds new directory. Side effect: for databases an empty file .empty.xml will be added in the new directory to make
     * the new directory persistent in the database.
     *
     * @param source BaseXSource in which new directory shall be added
     * @param path   path of new directory
     */
    public static void newDir(BaseXSource source, String path) {
        if (source.equals(BaseXSource.DATABASE)) {
            String resource = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<empty/>";
            String urlString = source.getProtocol() + ":" +
                    path + "/" + ArgonConst.EMPTY_FILE;
            try {
                URL url = new URL(urlString);
                ConnectionWrapper.save(url, resource.getBytes(), "UTF-8");
            } catch (IOException e1) {
                logger.error(e1);
            }
        } else {
            try (Connection connection = BaseXConnectionWrapper.getConnection()) {
                connection.newDir(source, path);
            } catch (Throwable io) {
                logger.error("Failed to create new directory: " + io.getMessage());
            }
        }
    }

} public class DialogTools {

    public static void CenterDialogRelativeToParent(Dialog dialog) {
        Dimension dialogSize = dialog.getSize();
        Container parent = dialog.getParent();
        Dimension parentSize = parent.getSize();

        int dx = (parentSize.width - dialogSize.width) / 2;
        int dy = (parentSize.height - dialogSize.height) / 2;

        dialog.setLocation(parent.getX() + dx, parent.getY() + dy);
    }

    public static void wrapAndShow(JDialog dialog, JPanel content, JFrame parentFrame) {
        wrap(dialog, content, parentFrame);
        dialog.setVisible(true);
    }

    public static void wrapAndShow(JDialog dialog, JPanel content, JFrame parentFrame, int width, int height) {
        wrap(dialog, content, parentFrame);
        dialog.setSize(width, height);
        dialog.setVisible(true);
    }

    private static void wrap(JDialog dialog, JPanel content, JFrame parentFrame) {
        content.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
        dialog.setContentPane(content);
        dialog.pack();
        dialog.setLocationRelativeTo(parentFrame);
        dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
    }

    public static JDialog getOxygenDialog(JFrame parentFrame, String title) {
        JDialog dialog = new JDialog(parentFrame, title);
        dialog.setModalityType(Dialog.ModalityType.APPLICATION_MODAL);
        // ToDo: image from map
        dialog.setIconImage(ImageUtils.createImage("/images/Oxygen16.png"));
        dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        return dialog;
    }

} public class Lang {

    private static final Logger logger = LogManager.getLogger(Lang.class);

    private static final String PATH = "/Argon";
    private static final String MISSING_KEY = "missing_key:";
    private static final String MISSING_RESOURCE = "missing_resource:";
    private static PluginResourceBundle bundle = null;

    private static final Map<Locale, Bundle> availableResourceBundles = new HashMap<>();
    static {
        loadBundle(Locale.GERMANY);
        loadBundle(Locale.UK);
    }
    private static Bundle currentBundle = availableResourceBundles.get(Locale.UK);

    public static void init() {
        init(Locale.UK);
    }

    public static void init(Locale locale) {
        setLocale(locale);
    }

    private static void loadBundle(final Locale locale) {
        try {
            final Bundle bundle = new Bundle(PATH, locale);
            availableResourceBundles.put(locale, bundle);
        } catch (final IOException ex) {
            logger.warn("Failed to read resource '" + PATH + "' for locale: '" + locale + "'", ex);
        } catch (final NullPointerException ex) {
            logger.warn("Missing resource '" + PATH + "' for locale: '" + locale + "'", ex);
        }
    }

    public static void setLocale(Locale locale) {
        if (locale.equals(Locale.GERMANY) || locale.equals(Locale.GERMAN)) {
            currentBundle = availableResourceBundles.get(Locale.GERMANY);
        } else {
            currentBundle = availableResourceBundles.get(Locale.UK);
        }
    }
    
    public static void init(StandalonePluginWorkspace wsa) {
        bundle = wsa.getResourceBundle();
    }

    public static String get(Keys key) {
        if (bundle != null) {
            return bundle.getMessage(key.name());
        }
        if (currentBundle != null) {
            String val = currentBundle.getString(key.name());
            if (val != null) {
                return val;
            } else {
                try {
                    throw new RuntimeException();
                } catch (RuntimeException e) {
                    logger.error("Missing key", e);
                }
                return MISSING_KEY + key;
            }
        } else {
            try {
                throw new RuntimeException();
            } catch (RuntimeException e) {
                logger.error("Missing bundle", e);
            }
            return MISSING_RESOURCE + key;
        }
    }

    public enum Keys {
        tree_root, tree_DB,
        tree_repo,
//        tree_restxq,
        cm_open, cm_checkout, cm_checkin, cm_adddb, cm_add, cm_addsimple,
        cm_addfile, cm_delete, cm_rename, cm_newversion, cm_showversion, cm_refresh, cm_search, cm_searchsimple, cm_find,
        cm_newdir, cm_save, cm_ok, cm_cancel, cm_tofile, cm_todb, cm_export, cm_checkinselected, cm_exit, cm_saveas,
        cm_replycomment,
        cm_runquery,
        cm_yes, cm_no, cm_all, cm_always, cm_never, cm_compare, cm_reset, cm_overwrite,
        cm_nosave,
        lbl_filename, lbl_filetype, lbl_filestocheck, lbl_delete, lbl_dir, lbl_searchpath, lbl_elements, lbl_text,
        lbl_attributes, lbl_attrbvalues, lbl_scope, lbl_options, lbl_whole, lbl_casesens, lbl_snippet,
        lbl_search1, lbl_search2, lbl_search3, lbl_search4, lbl_overwrite, lbl_version, lbl_revision, lbl_date, lbl_closed,
        lbl_connection, lbl_host, lbl_user, lbl_pwd, lbl_vcs, lbl_fe, lbl_dboptions, lbl_chop, lbl_ftindex, lbl_textindex,
        lbl_attributeindex, lbl_tokenindex, lbl_fixdefault, tt_fe,
        title_connection, title_connection2, title_history,
        warn_failednewdb, warn_failednewfile, warn_faileddeletedb, warn_faileddelete,
        warn_failedexport, warn_failednewversion, warn_norename, warn_resource, warn_storing, warn_locked, warn_nosnippet,
        warn_nofile, warn_failedsearch, warn_failedlist, warn_notransfer, warn_transfernoread,
        warn_transfernowrite1, warn_transfernowrite2, warn_connectionsettings1, warn_connectionsettings2, warn_settingspath1,
        warn_settingspath2, warn_settingspath3,
        msg_dbexists1, msg_dbexists2, msg_fileexists1, msg_fileexists2, msg_noquery, msg_noeditor, msg_checkpriordelete,
        msg_noupdate1, msg_noupdate2, msg_norename1, msg_norename2, msg_norename3, msg_transferlocked, msg_nameexists,
        msg_settingsexists, msg_noscopeselected,
        dlg_addfileinto, dlg_externalquery, dlg_checkedout, dlg_delete, dlg_newdir, dlg_replycomment, dlg_saveas, dlg_open,
        dlg_snippet, dlg_foundresources, dlg_overwrite, dlg_closed, dlg_overwritesetting, dlg_newsetting
    }

}
 public class WorkspaceUtils {

    public static final Logger logger = LogManager.getLogger(WorkspaceUtils.class);

    private static final PluginWorkspace workspaceAccess = PluginWorkspaceProvider.getPluginWorkspace();

    private static final int OVERWRITE_ALL = 2;
    private static final int OVERWRITE_YES = 1;
    private static final int OVERWRITE_ASK = 0;
    private static final int OVERWRITE_NO = -1;
    private static final int OVERWRITE_NONE = -2;

    private static JPanel treePanel;

    public static final Cursor WAIT_CURSOR = Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
    public static final Cursor DEFAULT_CURSOR = Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR);

    private WorkspaceUtils() {
    }

    public static byte[] getEditorByteContent(WSEditor editorAccess) {
        Document doc = getDocumentFromEditor(editorAccess);
        return doc.toString().getBytes(StandardCharsets.UTF_8);
    }

    private static byte[] getEditorContent(WSEditor editorAccess) throws IOException {
        byte[] content;
        try (InputStream contentStream = editorAccess.createContentInputStream()) {
            content = IOUtils.getBytesFromInputStream(contentStream);
        } catch (IOException ie) {
            logger.error(ie);
            content = new byte[0];
        }
        return content;
    }

    public static void setTreePanel(JPanel panel) {
        treePanel = panel;
    }

    /**
     * Extracts encoding from XML prologue in editor string content and the String content as second element,
     * returns empty string as first element if no prologue is found.
     *
     * @param editorAccess editor handle
     * @return encoding encoding and editor content as String array, empty if no encoding could be extracted
     */
    private static String[] editorStringEncoding(WSEditor editorAccess) {
        String encodingString[] = new String[2];
        String pageID = editorAccess.getCurrentPageID();
        if (!pageID.equals(EditorPageConstants.PAGE_TEXT))
            editorAccess.changePage(EditorPageConstants.PAGE_TEXT);
        WSTextEditorPage textPage = (WSTextEditorPage) editorAccess.getCurrentPage();
        Document doc = textPage.getDocument();
        if (!pageID.equals(EditorPageConstants.PAGE_TEXT))
            editorAccess.changePage(pageID);
        try {
            encodingString[1] = doc.getText(0, doc.getLength());
            encodingString[0] = XMLUtils.encodingFromPrologue(encodingString[1]);
        } catch (BadLocationException ex) {
            logger.error(ex);
            encodingString[0] = "";
        }
        return encodingString;
    }

    public static Document getDocumentFromEditor(WSEditor editorAccess) {
        boolean editorInAuthorMode = false;
        if (editorAccess.getCurrentPageID().equals(EditorPageConstants.PAGE_AUTHOR)) {
            editorInAuthorMode = true;
            editorAccess.changePage(EditorPageConstants.PAGE_TEXT);
        }
        WSTextEditorPage textPage = (WSTextEditorPage) editorAccess.getCurrentPage();
        Document doc = textPage.getDocument();
        if (editorInAuthorMode) {
            editorAccess.changePage(EditorPageConstants.PAGE_AUTHOR);
        }
        return doc;
    }

    public static void openURLString(String urlString) {
        try {
            URL argonURL = new URL(urlString);
            setCursor(WAIT_CURSOR);
            PluginWorkspaceProvider.getPluginWorkspace().open(argonURL);
            setCursor(DEFAULT_CURSOR);
        } catch (MalformedURLException e1) {
            logger.error(e1);
        }
    }

    public static void setCursor(Cursor cursor) {
        Component oxygenFrame = (Frame) workspaceAccess.getParentFrame();
        oxygenFrame.setCursor(cursor);
        if (treePanel != null)
            treePanel.setCursor(cursor);
    }

    public static int booleanDialog(PluginWorkspace pluginWorkspace,
                                    String title,
                                    String msg,
                                    String trueButton, int trueValue, String falseButton,
                                    int falseValue,
                                    int initial) {
        return pluginWorkspace.showConfirmDialog(
                title,
                msg,
                new String[]{trueButton, falseButton},
                new int[]{trueValue, falseValue},
                initial);
    }

    private static boolean checkOverwrite() {
        int save = booleanDialog(workspaceAccess,
                Lang.get(Lang.Keys.dlg_overwrite),
                Lang.get(Lang.Keys.lbl_overwrite),
                Lang.get(Lang.Keys.cm_yes), OVERWRITE_YES,
                Lang.get(Lang.Keys.cm_no), OVERWRITE_NO,
                0);
        return (save == OVERWRITE_YES);
    }

    private static int checkOverwriteAll() {
        return workspaceAccess.showConfirmDialog(Lang.get(Lang.Keys.dlg_overwrite), Lang.get(Lang.Keys.lbl_overwrite),
                new String[]{Lang.get(Lang.Keys.cm_yes), Lang.get(Lang.Keys.cm_always), Lang.get(Lang.Keys.cm_no), Lang.get(Lang.Keys.cm_never)},
                new int[]{OVERWRITE_YES, OVERWRITE_ALL, OVERWRITE_NO, OVERWRITE_NONE}, 2);
    }

    /**
     * Check for existence of a BaseX resource and show overwrite dialog if necessary
     *
     * @param source source of storage target
     * @param path   resource path of storage target
     * @return true if resource does not yet exist or user agreed to overwrite
     * @see OverwriteChecker
     */
    public static boolean newResourceOrOverwrite(BaseXSource source, String path) {
        boolean freeToSave = true;
        if (ConnectionWrapper.resourceExists(source, path)) {
            freeToSave = WorkspaceUtils.checkOverwrite();
        }
        return freeToSave;
    }

    /**
     * Store the content of an editor editorAccess to a BaseX resource url. Checks for encoding in prologue and byte code,
     * if none can be obtained assumes UTF-8 encoding.
     *
     * @param editorAccess editor handle
     * @param url          BaseX target url
     * @throws IOException BaseX connection can return exception
     */
    public static void saveEditorToBaseXURL(WSEditor editorAccess, URL url) throws IOException {
        byte[] content = WorkspaceUtils.getEditorContent(editorAccess);
        String[] encodingString = WorkspaceUtils.editorStringEncoding(editorAccess);
        if (encodingString[0].equals(""))
            encodingString[0] = XMLUtils.encodingFromBytes(content);
        if (!URLUtils.isXML(url) && (URLUtils.isBinary(url) || !IOUtils.isXML(content))) {
            ConnectionWrapper.save(true, url, content);
        } else {
            switch (encodingString[0]) {
                case "": {
                    ConnectionWrapper.save(url, IOUtils.returnUTF8Array(encodingString[1]), "UTF-8");
                    break;
                }
                case "UTF-8": {
                    ConnectionWrapper.save(url, content, "UTF-8");
                    break;
                }
                default:
                    ConnectionWrapper.save(url, IOUtils.convertToUTF8(content, encodingString[0]), encodingString[0]);
            }
        }
    }

    /**
     * The OverwriteChecker implements a way to check for multiple files to store for their existence and ask the user
     * whether existing files should be overwritten with "Always" and "Never" options.
     * <p>
     * For storing single files use the static method
     * {@link WorkspaceUtils#newResourceOrOverwrite(BaseXSource, String) newResourceOrOverwrite}
     */
    public static class OverwriteChecker {

        private int checkFlag;

        public OverwriteChecker() {
            checkFlag = OVERWRITE_ASK;
        }

        public boolean newResourceOrOverwrite(BaseXSource source, String path) {
            if (checkFlag == OVERWRITE_ALL)
                return true;
            if (ConnectionWrapper.resourceExists(source, path)) {
                if (checkFlag == OVERWRITE_NONE)
                    return false;
                int check;
                check = WorkspaceUtils.checkOverwriteAll();
                if ((check == OVERWRITE_ALL) || (check == OVERWRITE_NONE))
                    checkFlag = check;
                return ((check == OVERWRITE_YES) || (check == OVERWRITE_ALL));
            } else {
                return true;
            }

        }
    }

} public class ArgonOptionPage extends OptionPagePluginExtension {

    private static final Logger logger = LogManager.getLogger(ArgonOptionPage.class);

    /**
     * BaseX Keys
     */
    public static final String KEY_BASEX_CONNECTION_SETTING = "KEY_BASEX_CONNECTION_SETTING";
    public static final String KEY_BASEX_HOST = "KEY_BASEX_HOST";
    public static final String KEY_BASEX_HTTP_PORT = "KEY_BASEX_HTTP_PORT";
    public static final String KEY_BASEX_TCP_PORT = "KEY_BASEX_TCP_PORT";
    public static final String KEY_BASEX_USERNAME = "KEY_BASEX_USERNAME";
    public static final String KEY_BASEX_PASSWORD = "KEY_BASEX_PASSWORD";
    public static final String KEY_BASEX_CONNECTION = "KEY_BASEX_CONNECTION";
    public static final String KEY_BASEX_VERSIONING = "KEY_BASEX_VERSIONING";
    public static final String KEY_BASEX_FILTER_EXCLUDE = "KEY_BASEX_FILTER_EXCLUDE";
    public static final String KEY_BASEX_LOGFILE = "KEY_BASEX_LOGFILE";
    public static final String KEY_BASEX_DB_CREATE_CHOP = "KEY_BASEX_DB_CREATE_CHOP";
    public static final String KEY_BASEX_DB_CREATE_FTINDEX = "KEY_BASEX_DB_CREATE_FTINDEX";
    public static final String KEY_BASEX_DB_CREATE_TEXTINDEX = "KEY_BASEX_DB_CREATE_TEXTINDEX";
    public static final String KEY_BASEX_DB_CREATE_ATTRINDEX = "KEY_BASEX_DB_CREATE_ATTRINDEX";
    public static final String KEY_BASEX_DB_CREATE_TOKENINDEX = "KEY_BASEX_DB_CREATE_TOKENINDEX";

    private static final String DEF_BASEX_CONNECTION_SETTING = "default";
    private static final String DEF_BASEX_HOST = "localhost:8984/rest";
    private static final String DEF_BASEX_HTTP_PORT = "8984";
    private static final String DEF_BASEX_TCP_PORT = "1984";
    private static final String DEF_BASEX_USERNAME = "admin";
    private static final String DEF_BASEX_PASSWORD = "admin";
    private static final String DEF_BASEX_CONNECTION = "HTTP";
    private static final String DEF_BASEX_VERSIONING = "true";
    private static final String DEF_BASEX_FILTER_EXCLUDE = "";
    private static final String DEF_BASEX_LOGFILE = System.getProperty("user.home") + "/argon.log";
    private static final String DEF_BASEX_DB_CREATE_CHOP = "false";
    private static final String DEF_BASEX_DB_CREATE_FTINDEX = "false";
    private static final String DEF_BASEX_DB_CREATE_TEXTINDEX = "false";
    private static final String DEF_BASEX_DB_CREATE_ATTRINDEX = "false";
    private static final String DEF_BASEX_DB_CREATE_TOKENINDEX = "false";

    private static final String CONNECTION_SETTING_PATH = System.getProperty("user.home") + "/argon";
    private static final String CONNECTION_SETTING_FILE_TYPE = ".properties";

    private static final String CS_NAME = "CS_NAME";
    private static final String CS_HOST = "CS_HOST";
    private static final String CS_USER = "CS_USER";
    private static final String CS_PWD = "CS_PWD";
    private static final String CS_FE = "CS_FE";
    private static final String CS_VCS = "CS_VCS";
    private static final String CS_CHOP = "CS_CHOP";
    private static final String CS_FT = "CS_FT";
    private static final String CS_TEXT = "CS_TEXT";
    private static final String CS_ATTR = "CS_ATTR";
    private static final String CS_TOKEN = "CS_TOKEN";

    /**
     * BaseX JTextFields
     */
    private JComboBox<String> baseXConnectionSettingsComboBox;
    private JTextField baseXHostTextField;
    private JTextField baseXHttpPortTextField;
    private JTextField baseXTcpPortTextField;
    private JTextField baseXUsernameTextField;
    private JTextField baseXPasswordTextField;
    private JComboBox baseXConnectionTypeComboBox;
    private JCheckBox baseXVersioningCheckBox;
    private JTextField baseXFilterExcludeTextField;
    private JTextField baseXLogfileTextField;
    private JCheckBox baseXDBCreateChopCheckBox;
    private JCheckBox baseXDBCreateFTIndexCheckBox;
    private JCheckBox baseXDBCreateTextIndexCheckBox;
    private JCheckBox baseXDBCreateAttrIndexCheckBox;
    private JCheckBox baseXDBCreateTokenIndexCheckBox;

    private List<String[]> connectionSettings;
    private List<String> connectionSettingNames;

    /**
     * @see ro.sync.exml.plugin.option.OptionPagePluginExtension#apply(ro.sync.exml.workspace.api.PluginWorkspace)
     */
    @Override
    public void apply(PluginWorkspace pluginWorkspace) {
        if (!((String) baseXConnectionSettingsComboBox.getSelectedItem()).
                matches(FileNameFieldListener.FILE_NAME_CHARS_WITHOUT_EXTENSION)) {
            java.awt.Toolkit.getDefaultToolkit().beep();
            pluginWorkspace.showErrorMessage(Lang.get(Lang.Keys.warn_connectionsettings1) + "\n" +
                    Lang.get(Lang.Keys.warn_connectionsettings2));
        } else {
            final WSOptionsStorage optionsStorage = pluginWorkspace.getOptionsStorage();

            // save BaseX configs in the option storage
            settingsChangedOverwrite();
            
            optionsStorage.setOption(KEY_BASEX_CONNECTION_SETTING,
                    !"".equals(baseXConnectionSettingsComboBox.getSelectedItem().toString()) ?
                            baseXConnectionSettingsComboBox.getSelectedItem().toString() : DEF_BASEX_CONNECTION_SETTING);

            optionsStorage.setOption(KEY_BASEX_HOST,
                    !"".equals(baseXHostTextField.getText()) ? baseXHostTextField.getText() : DEF_BASEX_HOST);

/*        pluginWorkspace.getOptionsStorage().setOption(KEY_BASEX_HTTP_PORT,
                !"".equals(baseXHttpPortTextField.getText()) ? baseXHttpPortTextField.getText() : DEF_BASEX_HTTP_PORT);

        pluginWorkspace.getOptionsStorage().setOption(KEY_BASEX_TCP_PORT,
                !"".equals(baseXTcpPortTextField.getText()) ? baseXTcpPortTextField.getText() : DEF_BASEX_TCP_PORT);*/

            optionsStorage.setOption(KEY_BASEX_USERNAME,
                    !"".equals(baseXUsernameTextField.getText()) ? baseXUsernameTextField.getText() : DEF_BASEX_USERNAME);

            optionsStorage.setOption(KEY_BASEX_PASSWORD,
                    !"".equals(baseXPasswordTextField.getText()) ? baseXPasswordTextField.getText() : DEF_BASEX_PASSWORD);

/*        pluginWorkspace.getOptionsStorage().setOption(KEY_BASEX_CONNECTION,
                baseXConnectionTypeComboBox.getSelectedItem().toString());*/

            optionsStorage.setOption(KEY_BASEX_VERSIONING,
                    baseXVersioningCheckBox.isSelected() ? "true" : "false");

            optionsStorage.setOption(KEY_BASEX_FILTER_EXCLUDE, baseXFilterExcludeTextField.getText());

/*        pluginWorkspace.getOptionsStorage().setOption(KEY_BASEX_LOGFILE,
                !"".equals(baseXLogfileTextField.getText()) ? baseXLogfileTextField.getText() : DEF_BASEX_LOGFILE);*/

            optionsStorage.setOption(KEY_BASEX_DB_CREATE_CHOP,
                    baseXDBCreateChopCheckBox.isSelected() ? "true" : "false");

            optionsStorage.setOption(KEY_BASEX_DB_CREATE_FTINDEX,
                    baseXDBCreateFTIndexCheckBox.isSelected() ? "true" : "false");

            optionsStorage.setOption(KEY_BASEX_DB_CREATE_TEXTINDEX,
                    baseXDBCreateTextIndexCheckBox.isSelected() ? "true" : "false");

            optionsStorage.setOption(KEY_BASEX_DB_CREATE_ATTRINDEX,
                    baseXDBCreateAttrIndexCheckBox.isSelected() ? "true" : "false");

            optionsStorage.setOption(KEY_BASEX_DB_CREATE_TOKENINDEX,
                    baseXDBCreateTokenIndexCheckBox.isSelected() ? "true" : "false");
        }
    }

    /**
     * @see ro.sync.exml.plugin.option.OptionPagePluginExtension#restoreDefaults()
     */
    @Override
    public void restoreDefaults() {
        // Reset the text fields values. Empty string is used to map the <null> default values of the options.
        baseXConnectionSettingsComboBox.setSelectedItem(0);
        baseXHostTextField.setText(DEF_BASEX_HOST);
/*        baseXHttpPortTextField.setText(DEF_BASEX_HTTP_PORT);
        baseXTcpPortTextField.setText(DEF_BASEX_TCP_PORT);*/
        baseXUsernameTextField.setText(DEF_BASEX_USERNAME);
        baseXPasswordTextField.setText(DEF_BASEX_PASSWORD);
/*        baseXConnectionTypeComboBox.setSelectedItem(DEF_BASEX_CONNECTION);*/
        baseXVersioningCheckBox.setSelected(Boolean.parseBoolean(DEF_BASEX_VERSIONING));
        baseXFilterExcludeTextField.setText(DEF_BASEX_FILTER_EXCLUDE);
/*        baseXLogfileTextField.setText(DEF_BASEX_LOGFILE);*/
        baseXDBCreateChopCheckBox.setSelected(Boolean.parseBoolean(DEF_BASEX_DB_CREATE_CHOP));
        baseXDBCreateFTIndexCheckBox.setSelected(Boolean.parseBoolean(DEF_BASEX_DB_CREATE_FTINDEX));
        baseXDBCreateTextIndexCheckBox.setSelected(Boolean.parseBoolean(DEF_BASEX_DB_CREATE_TEXTINDEX));
        baseXDBCreateAttrIndexCheckBox.setSelected(Boolean.parseBoolean(DEF_BASEX_DB_CREATE_ATTRINDEX));
        baseXDBCreateTokenIndexCheckBox.setSelected(Boolean.parseBoolean(DEF_BASEX_DB_CREATE_TOKENINDEX));
    }

    /**
     * @see ro.sync.exml.plugin.option.OptionPagePluginExtension#getTitle()
     */
    @Override
    public String getTitle() {
        return "BaseX Configuration";
    }

    /**
     * @see ro.sync.exml.plugin.option.OptionPagePluginExtension#init(ro.sync.exml.workspace.api.PluginWorkspace)
     */
    @Override
    public JComponent init(final PluginWorkspace pluginWorkspace) {

        /**
         * Initial Values
         */
        final String baseXConnectionSetting = getOption(KEY_BASEX_CONNECTION_SETTING, false);
        String baseXHost = getOption(KEY_BASEX_HOST, false);
/*        String baseXHttpPort = getOption(KEY_BASEX_HTTP_PORT, false);*/
/*        String baseXTcpPort = getOption(KEY_BASEX_TCP_PORT, false)*/
        String baseXUsername = getOption(KEY_BASEX_USERNAME, false);
        String baseXPassword = getOption(KEY_BASEX_PASSWORD, false);
/*        String baseXConnection = getOption(KEY_BASEX_CONNECTION, false);*/
        String baseXVersioning = getOption(KEY_BASEX_VERSIONING, false);
        String baseXFilterExclude = getOption(KEY_BASEX_FILTER_EXCLUDE, false);
/*        String baseXLogfile = getOption(KEY_BASEX_LOGFILE, false);*/
        String baseXDBCreateChop = getOption(KEY_BASEX_DB_CREATE_CHOP, false);
        String baseXDBCreateFTIndex = getOption(KEY_BASEX_DB_CREATE_FTINDEX, false);
        String baseXDBCreateTextIndex = getOption(KEY_BASEX_DB_CREATE_TEXTINDEX, false);
        String baseXDBCreateAttrIndex = getOption(KEY_BASEX_DB_CREATE_ATTRINDEX, false);
        String baseXDBCreateTokenIndex = getOption(KEY_BASEX_DB_CREATE_TOKENINDEX, false);

        connectionSettings = loadConnectionSettings();
        connectionSettingNames = new ArrayList<>();
        for (String[] setting : connectionSettings) {
            connectionSettingNames.add(setting[0]);
        }


        /**
         * Setup of Option Pane
         */
        GridBagConstraints c = new GridBagConstraints();
        JPanel panel = new JPanel(new GridBagLayout());
        JLabel saveTmpLocationLbl = new JLabel(Lang.get(Lang.Keys.title_connection2));
        saveTmpLocationLbl.setFont(saveTmpLocationLbl.getFont().deriveFont(Font.BOLD));

        c.gridx = 0;
        c.gridy = 0;
        c.weightx = 0;
        c.weighty = 0;
        c.anchor = GridBagConstraints.WEST;
        panel.add(saveTmpLocationLbl, c);


        /**
         * BaseX Connection Settings List
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXConnectionSettingsComboBoxLbl = new JLabel(Lang.get(Lang.Keys.lbl_connection));
        panel.add(baseXConnectionSettingsComboBoxLbl, c);

        baseXConnectionSettingsComboBox = new JComboBox(connectionSettingNames.toArray());
        baseXConnectionSettingsComboBox.setEditable(true);
        baseXConnectionSettingsComboBox.addActionListener(e -> {
            int newSelection = ((JComboBox) e.getSource()).getSelectedIndex();
            if (newSelection != -1) {  // one of the old entries was selected
                try {
                    baseXHostTextField.setText(connectionSettings.get(newSelection)[1]);
                    baseXUsernameTextField.setText(connectionSettings.get(newSelection)[2]);
                    baseXPasswordTextField.setText(connectionSettings.get(newSelection)[3]);
                    baseXVersioningCheckBox.setSelected(connectionSettings.get(newSelection)[4].equals("true"));
                    baseXDBCreateChopCheckBox.setSelected(connectionSettings.get(newSelection)[5].equals("true"));
                    baseXDBCreateFTIndexCheckBox.setSelected(connectionSettings.get(newSelection)[6].equals("true"));
                    baseXDBCreateTextIndexCheckBox.setSelected(connectionSettings.get(newSelection)[7].equals("true"));
                    baseXDBCreateAttrIndexCheckBox.setSelected(connectionSettings.get(newSelection)[8].equals("true"));
                    baseXDBCreateTokenIndexCheckBox.setSelected(connectionSettings.get(newSelection)[9].equals("true"));
                    baseXFilterExcludeTextField.setText(connectionSettings.get(newSelection)[10]);
                } catch (NullPointerException | IndexOutOfBoundsException ex) {
                }
            }
        });
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXConnectionSettingsComboBox, c);
        c.gridx = 0;
        c.gridy++;
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);
        c.gridx = 0;
        c.gridy++;
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);
        c.gridx = 0;
        c.gridy++;
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);

        /**
         * BaseX Hostname
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXHostTextFieldLbl = new JLabel(Lang.get(Lang.Keys.lbl_host));
        panel.add(baseXHostTextFieldLbl, c);

        baseXHostTextField = new JTextField();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXHostTextField, c);


        /**
         * BaseX Http Port
         */
/*        c.gridx = 0;
        c.gridy++;
        JLabel baseXHttpPortTextFieldLbl = new JLabel("BaseX HTTP Port:");
        panel.add(baseXHttpPortTextFieldLbl, c);

        baseXHttpPortTextField = new JTextField();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXHttpPortTextField, c);*/


        /**
         * BaseX TCP Port
         */
/*        c.gridx = 0;
        c.gridy++;
        JLabel baseXTcpPortTextFieldLbl = new JLabel("BaseX TCP Port:");
        panel.add(baseXTcpPortTextFieldLbl, c);

        baseXTcpPortTextField = new JTextField();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXTcpPortTextField, c);*/


        /**
         * BaseX Username
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXUsernameTextFieldLbl = new JLabel(Lang.get(Lang.Keys.lbl_user));
        panel.add(baseXUsernameTextFieldLbl, c);

        baseXUsernameTextField = new JTextField();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXUsernameTextField, c);


        /**
         * BaseX Password
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXPasswordTextFieldLbl = new JLabel(Lang.get(Lang.Keys.lbl_pwd));
        panel.add(baseXPasswordTextFieldLbl, c);

        baseXPasswordTextField = new JTextField();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXPasswordTextField, c);


        /**
         * BaseX Connection type
         */
/*        c.gridx = 0;
        c.gridy++;
        JLabel baseXConnectionTypeRadioFrameLbl = new JLabel("Connection type:");
        panel.add(baseXConnectionTypeRadioFrameLbl, c);

        String[] connectionTypes = { "HTTP" , "TCP" };
        baseXConnectionTypeComboBox = new JComboBox<>(connectionTypes);
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXConnectionTypeComboBox, c);*/

        c.gridx = 0;
        c.gridy++;
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);
        /**
         * BaseX Versioning
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXVersioningCheckBoxLbl = new JLabel(Lang.get(Lang.Keys.lbl_vcs));
        panel.add(baseXVersioningCheckBoxLbl, c);

        baseXVersioningCheckBox = new JCheckBox();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXVersioningCheckBox, c);

        c.gridx = 0;
        c.gridy++;
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);


        /**
         * DBs to be excluded from filter
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXFilterExcludeTextFieldLbl = new JLabel(Lang.get(Lang.Keys.lbl_fe));
        panel.add(baseXFilterExcludeTextFieldLbl, c);

        baseXFilterExcludeTextField = new JTextField();
        baseXFilterExcludeTextField.setToolTipText(Lang.get(Lang.Keys.tt_fe));
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXFilterExcludeTextField, c);

        /**
         * BaseX Logfile
         */
/*
        c.gridx = 0;
        c.gridy++;
        JLabel baseXLogfileTextFieldLbl = new JLabel("Argon Logfile:");
        panel.add(baseXLogfileTextFieldLbl, c);

        baseXLogfileTextField = new JTextField();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXLogfileTextField, c);


        JButton chooseBaseXLogfileBtn = new JButton("Choose");
        c.gridx ++;
        c.weightx = 0;
        c.insets = new Insets(0, 0, 0, 0);
        c.fill = GridBagConstraints.NONE;
        panel.add(chooseBaseXLogfileBtn, c);

        chooseBaseXLogfileBtn.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                File dir = pluginWorkspace.chooseDirectory();
                if (dir != null) {
                    baseXLogfileTextField.setText(dir.getAbsolutePath() + "/argon.log");
                }
            }
        });
*/

        c.gridx = 0;
        c.gridy++;
        panel.add(new JSeparator(JSeparator.HORIZONTAL), c);
        /**
         * BaseX DB Create Options
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXDBCreateOptionsLbl = new JLabel(Lang.get(Lang.Keys.lbl_dboptions));
        baseXDBCreateOptionsLbl.setFont(baseXDBCreateOptionsLbl.getFont().deriveFont(Font.BOLD));
        panel.add(baseXDBCreateOptionsLbl, c);

        /**
         * BaseX DB Create Chop Option
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXDBCreateChopCheckBoxLbl = new JLabel(Lang.get(Lang.Keys.lbl_chop));
        panel.add(baseXDBCreateChopCheckBoxLbl, c);

        baseXDBCreateChopCheckBox = new JCheckBox();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXDBCreateChopCheckBox, c);

        /**
         * BaseX DB Create FTIndex Option
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXDBCreateFTIndexCheckBoxLbl = new JLabel(Lang.get(Lang.Keys.lbl_ftindex));
        panel.add(baseXDBCreateFTIndexCheckBoxLbl, c);

        baseXDBCreateFTIndexCheckBox = new JCheckBox();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXDBCreateFTIndexCheckBox, c);

        /**
         * BaseX DB Create TextIndex Option
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXDBCreateTextIndexCheckBoxLbl = new JLabel(Lang.get(Lang.Keys.lbl_textindex));
        panel.add(baseXDBCreateTextIndexCheckBoxLbl, c);

        baseXDBCreateTextIndexCheckBox = new JCheckBox();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXDBCreateTextIndexCheckBox, c);

        /**
         * BaseX DB Create AttrIndex Option
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXDBCreateAttrIndexCheckBoxLbl = new JLabel(Lang.get(Lang.Keys.lbl_attributeindex));
        panel.add(baseXDBCreateAttrIndexCheckBoxLbl, c);

        baseXDBCreateAttrIndexCheckBox = new JCheckBox();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXDBCreateAttrIndexCheckBox, c);

        /**
         * BaseX DB Create TokenIndex Option
         */
        c.gridx = 0;
        c.gridy++;
        JLabel baseXDBCreateTokenIndexCheckBoxLbl = new JLabel(Lang.get(Lang.Keys.lbl_tokenindex));
        panel.add(baseXDBCreateTokenIndexCheckBoxLbl, c);

        baseXDBCreateTokenIndexCheckBox = new JCheckBox();
        c.gridx++;
        c.weightx = 1;
        c.fill = GridBagConstraints.HORIZONTAL;
        c.insets = new Insets(0, 5, 0, 5);
        panel.add(baseXDBCreateTokenIndexCheckBox, c);

        c.gridx = 0;
        c.gridy++;
        c.gridwidth = 3;
        c.weightx = 1;
        c.weighty = 1;
        c.fill = GridBagConstraints.BOTH;
        panel.add(new JPanel(), c);

        /**
         * Initialize the fields with the stored options.
         */
        baseXConnectionSettingsComboBox.setSelectedIndex(0);
        baseXConnectionSettingsComboBox.setSelectedItem(baseXConnectionSetting);
        baseXHostTextField.setText(baseXHost != null ? baseXHost : "");
/*        baseXHttpPortTextField.setText(baseXHttpPort != null ? baseXHttpPort : "");*/
/*        baseXTcpPortTextField.setText(baseXTcpPort != null ? baseXTcpPort : "");*/
        baseXUsernameTextField.setText(baseXUsername != null ? baseXUsername : "");
        baseXPasswordTextField.setText(baseXPassword != null ? baseXPassword : "");
/*        if (baseXConnection.equals(connectionTypes[1])) {
            baseXConnectionTypeComboBox.setSelectedItem(connectionTypes[1]);
        } else {
            baseXConnectionTypeComboBox.setSelectedItem(connectionTypes[0]);
        }*/
        baseXVersioningCheckBox.setSelected(Boolean.parseBoolean(baseXVersioning));
        baseXFilterExcludeTextField.setText(baseXFilterExclude != null ? baseXFilterExclude : "");
/*        baseXLogfileTextField.setText(baseXLogfile != null ? baseXLogfile : "");*/
        baseXDBCreateChopCheckBox.setSelected(Boolean.parseBoolean(baseXDBCreateChop));
        baseXDBCreateFTIndexCheckBox.setSelected(Boolean.parseBoolean(baseXDBCreateFTIndex));
        baseXDBCreateTextIndexCheckBox.setSelected(Boolean.parseBoolean(baseXDBCreateTextIndex));
        baseXDBCreateAttrIndexCheckBox.setSelected(Boolean.parseBoolean(baseXDBCreateAttrIndex));
        baseXDBCreateTokenIndexCheckBox.setSelected(Boolean.parseBoolean(baseXDBCreateTokenIndex));

        return panel;
    }

    public static String getOption(String key, boolean defaults) {
        String defaultValue;
        switch (key) {
            case KEY_BASEX_CONNECTION_SETTING:
                defaultValue = DEF_BASEX_CONNECTION_SETTING;
                break;
            case KEY_BASEX_HOST:
                defaultValue = DEF_BASEX_HOST;
                break;
            case KEY_BASEX_HTTP_PORT:
                defaultValue = DEF_BASEX_HTTP_PORT;
                break;
            case KEY_BASEX_TCP_PORT:
                defaultValue = DEF_BASEX_TCP_PORT;
                break;
            case KEY_BASEX_USERNAME:
                defaultValue = DEF_BASEX_USERNAME;
                break;
            case KEY_BASEX_PASSWORD:
                defaultValue = DEF_BASEX_PASSWORD;
                break;
            case KEY_BASEX_CONNECTION:
                defaultValue = DEF_BASEX_CONNECTION;
                break;
            case KEY_BASEX_VERSIONING:
                defaultValue = DEF_BASEX_VERSIONING;
                break;
            case KEY_BASEX_FILTER_EXCLUDE:
                defaultValue = DEF_BASEX_FILTER_EXCLUDE;
                break;
            case KEY_BASEX_LOGFILE:
                defaultValue = DEF_BASEX_LOGFILE;
                break;
            case KEY_BASEX_DB_CREATE_CHOP:
                defaultValue = DEF_BASEX_DB_CREATE_CHOP;
                break;
            case KEY_BASEX_DB_CREATE_FTINDEX:
                defaultValue = DEF_BASEX_DB_CREATE_FTINDEX;
                break;
            case KEY_BASEX_DB_CREATE_TEXTINDEX:
                defaultValue = DEF_BASEX_DB_CREATE_TEXTINDEX;
                break;
            case KEY_BASEX_DB_CREATE_ATTRINDEX:
                defaultValue = DEF_BASEX_DB_CREATE_ATTRINDEX;
                break;
            case KEY_BASEX_DB_CREATE_TOKENINDEX:
                defaultValue = DEF_BASEX_DB_CREATE_TOKENINDEX;
                break;
            default:
                defaultValue = "empty option";
        }
        if (defaults) {
            return defaultValue;
        } else {
            PluginWorkspace pluginWorkspace = PluginWorkspaceProvider.getPluginWorkspace();
            if (pluginWorkspace != null) {
                WSOptionsStorage store = pluginWorkspace.getOptionsStorage();
                if (store != null)
                    return store.getOption(key, defaultValue);
                else {
                    logger.error("Plugin error - no option storage accessible");
                    return defaultValue;
                }
            } else {
                logger.error("Plugin error - no plugin workspace accessible");
                return defaultValue;
            }
        }
    }

    private void settingsChangedOverwrite() {
        final int index = baseXConnectionSettingsComboBox.getSelectedIndex();
        if (index == -1) { // new
            storeConnectionSettings();
            updateSettingsList((String) baseXConnectionSettingsComboBox.getSelectedItem(), index);
        } else {
            try {
                if (!baseXHostTextField.getText().equals(connectionSettings.get(index)[1]) ||
                        !baseXUsernameTextField.getText().equals(connectionSettings.get(index)[2]) ||
                        !baseXPasswordTextField.getText().equals(connectionSettings.get(index)[3]) ||
                        !Boolean.toString(baseXVersioningCheckBox.isSelected()).equals(connectionSettings.get(index)[4]) ||
                        !Boolean.toString(baseXDBCreateChopCheckBox.isSelected()).equals(connectionSettings.get(index)[5]) ||
                        !Boolean.toString(baseXDBCreateFTIndexCheckBox.isSelected()).equals(connectionSettings.get(index)[6]) ||
                        !Boolean.toString(baseXDBCreateTextIndexCheckBox.isSelected()).equals(connectionSettings.get(index)[7]) ||
                        !Boolean.toString(baseXDBCreateAttrIndexCheckBox.isSelected()).equals(connectionSettings.get(index)[8]) ||
                        !Boolean.toString(baseXDBCreateTokenIndexCheckBox.isSelected()).equals(connectionSettings.get(index)[9]) ||
                        !baseXFilterExcludeTextField.getText().equals(connectionSettings.get(index)[10])) {
                    int overwrite;
                    if (index == 0) {
                        overwrite = 1;
                    } else {
                        overwrite = booleanDialog(PluginWorkspaceProvider.getPluginWorkspace(),
                                Lang.get(Lang.Keys.dlg_overwritesetting),
                                Lang.get(Lang.Keys.msg_settingsexists),
                                Lang.get(Lang.Keys.cm_overwrite), 0,
                                Lang.get(Lang.Keys.cm_rename), 1,
                                0);
                    }
                    if (overwrite == 0) {
                        storeConnectionSettings();
                        updateSettingsList((String) baseXConnectionSettingsComboBox.getSelectedItem(), index);
                    } else {
                        JFrame parentFrame = (JFrame) ((new AuthorComponentFactory()).getWorkspaceUtilities().getParentFrame());
                        JDialog renameDialog = DialogTools.getOxygenDialog(parentFrame, Lang.get(Lang.Keys.dlg_newsetting));
                        JPanel content = new JPanel(new BorderLayout(10, 10));
                        content.add(new JLabel(Lang.get(Lang.Keys.lbl_fixdefault)));
                        JTextField settingNameTextField = new JTextField();
                        settingNameTextField.getDocument().addDocumentListener(new FileNameFieldListener(settingNameTextField, true));
                        content.add(settingNameTextField, BorderLayout.NORTH);
                        AbstractAction renameThisAction = new AbstractAction() {
                            @Override
                            public void actionPerformed(ActionEvent e) {
                                String newName = settingNameTextField.getText();
                                if (connectionSettingNames.contains(newName)) {
                                    PluginWorkspaceProvider.getPluginWorkspace().showErrorMessage(Lang.get(Lang.Keys.msg_nameexists));
                                } else {
                                    if (newName.equals("")) {
                                        storeConnectionSettings();
                                        updateSettingsList((String) baseXConnectionSettingsComboBox.getSelectedItem(), index);
                                    } else {
                                        baseXConnectionSettingsComboBox.addItem(settingNameTextField.getText());
                                        baseXConnectionSettingsComboBox.setSelectedItem(settingNameTextField.getText());
                                        storeConnectionSettings();
                                        updateSettingsList((String) baseXConnectionSettingsComboBox.getSelectedItem(), -1);
                                    }
                                    renameDialog.dispose();
                                }
                            }
                        };
                        settingNameTextField.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "confirm");
                        settingNameTextField.getActionMap().put("confirm", renameThisAction);

                        JPanel btnPanel = new JPanel();
                        JButton addBtn = new JButton(renameThisAction);
                        addBtn.setText(Lang.get(Lang.Keys.cm_ok));
                        btnPanel.add(addBtn, BorderLayout.WEST);
                        JButton cancelBtn = new JButton(new CloseDialogAction(Lang.get(Lang.Keys.cm_nosave), renameDialog));
                        btnPanel.add(cancelBtn, BorderLayout.EAST);
                        content.add(btnPanel, BorderLayout.SOUTH);
                        DialogTools.wrapAndShow(renameDialog, content, parentFrame);
                    }
                }
            } catch (NullPointerException | IndexOutOfBoundsException ex) {
                storeConnectionSettings();
            }
        }
        int newIndex;
        if (index == -1)
            newIndex = connectionSettingNames.size() - 1;
        else
            newIndex = index;
        baseXConnectionSettingsComboBox.removeAllItems();
        for (String newName : connectionSettingNames) {
            baseXConnectionSettingsComboBox.addItem(newName);
        }
        baseXConnectionSettingsComboBox.setSelectedIndex(newIndex);
    }

    private void updateSettingsList(String name, int index) {
        final String[] newSetting = {
                (String) baseXConnectionSettingsComboBox.getSelectedItem(),
                baseXHostTextField.getText(),
                baseXUsernameTextField.getText(),
                baseXPasswordTextField.getText(),
                Boolean.toString(baseXVersioningCheckBox.isSelected()),
                Boolean.toString(baseXDBCreateChopCheckBox.isSelected()),
                Boolean.toString(baseXDBCreateFTIndexCheckBox.isSelected()),
                Boolean.toString(baseXDBCreateTextIndexCheckBox.isSelected()),
                Boolean.toString(baseXDBCreateAttrIndexCheckBox.isSelected()),
                Boolean.toString(baseXDBCreateTokenIndexCheckBox.isSelected()),
                baseXFilterExcludeTextField.getText()
        };
        if (index == -1) {
            connectionSettingNames.add(name);
            connectionSettings.add(newSetting);
            index = connectionSettingNames.size() - 1;
        } else {
            connectionSettingNames.set(index, name);
            connectionSettings.set(index, newSetting);
        }
    }

    private static List loadConnectionSettings() {
        final List<String[]> connectionSettings = new ArrayList<>();
        final String[] conn = {"default", DEF_BASEX_HOST, DEF_BASEX_USERNAME, DEF_BASEX_PASSWORD, DEF_BASEX_VERSIONING,
                DEF_BASEX_DB_CREATE_CHOP, DEF_BASEX_DB_CREATE_FTINDEX, DEF_BASEX_DB_CREATE_TEXTINDEX,
                DEF_BASEX_DB_CREATE_ATTRINDEX, DEF_BASEX_DB_CREATE_TOKENINDEX, DEF_BASEX_FILTER_EXCLUDE};
        connectionSettings.add(conn);
        final File settingsPath = new File(CONNECTION_SETTING_PATH);
        if (FileUtils.directoryExists(settingsPath)) {
            final String[] fileList = settingsPath.list((dir, fileName) -> fileName.toLowerCase().endsWith(CONNECTION_SETTING_FILE_TYPE));
            if (fileList != null) {
                for (String settingsFile : fileList) {
                    final Properties properties = new Properties();
                    try (InputStream in = new BufferedInputStream(
                            new FileInputStream(CONNECTION_SETTING_PATH + "/" + settingsFile))) {
                        properties.load(in);
                        final String[] connSetting = {properties.getProperty(CS_NAME), properties.getProperty(CS_HOST),
                                properties.getProperty(CS_USER), properties.getProperty(CS_PWD), properties.getProperty(CS_VCS),
                                properties.getProperty(CS_CHOP), properties.getProperty(CS_FT), properties.getProperty(CS_TEXT),
                                properties.getProperty(CS_ATTR), properties.getProperty(CS_TOKEN), properties.getProperty(CS_FE)};
                        connectionSettings.add(connSetting);
                    } catch (IOException ioe) {
                        logger.debug(ioe.getMessage());
                    }
                }
            }
        }
        return connectionSettings;
    }

    private void storeConnectionSettings() {
        final File settingsPath = new File(CONNECTION_SETTING_PATH);
        boolean noDirectory = false;
        if (!FileUtils.directoryExists(settingsPath)) {
            if (!settingsPath.mkdir()) {
                noDirectory = true;
                PluginWorkspaceProvider.getPluginWorkspace().
                        showErrorMessage(Lang.get(Lang.Keys.warn_settingspath1) + "\n" + Lang.get(Lang.Keys.warn_settingspath2));
            }
        }
        if (!noDirectory) {
            final String fileName = CONNECTION_SETTING_PATH + "/" +
                    baseXConnectionSettingsComboBox.getSelectedItem() + CONNECTION_SETTING_FILE_TYPE;
            final File settingsFile = new File(fileName);
            final Properties properties = new Properties();
            properties.setProperty(CS_NAME, (String) baseXConnectionSettingsComboBox.getSelectedItem());
            properties.setProperty(CS_HOST, baseXHostTextField.getText());
            properties.setProperty(CS_USER, baseXUsernameTextField.getText());
            properties.setProperty(CS_PWD, baseXPasswordTextField.getText());
            properties.setProperty(CS_VCS, baseXVersioningCheckBox.isSelected() ? "true" : "false");
            properties.setProperty(CS_CHOP, baseXDBCreateChopCheckBox.isSelected() ? "true" : "false");
            properties.setProperty(CS_FT, baseXDBCreateFTIndexCheckBox.isSelected() ? "true" : "false");
            properties.setProperty(CS_TEXT, baseXDBCreateTextIndexCheckBox.isSelected() ? "true" : "false");
            properties.setProperty(CS_ATTR, baseXDBCreateAttrIndexCheckBox.isSelected() ? "true" : "false");
            properties.setProperty(CS_TOKEN, baseXDBCreateTokenIndexCheckBox.isSelected() ? "true" : "false");
            properties.setProperty(CS_FE, baseXFilterExcludeTextField.getText());
            try (FileOutputStream fileOut = new FileOutputStream(settingsFile)) {
                properties.store(fileOut, "Favorite Things");
            } catch (IOException ioe) {
                logger.error(ioe.getMessage());
                PluginWorkspaceProvider.getPluginWorkspace().
                        showErrorMessage(Lang.get(Lang.Keys.warn_settingspath3) + "\n" + fileName);
            }
        }
    }


}
import de.axxepta.oxygen.api.ArgonConst;
import de.axxepta.oxygen.api.BaseXResource;
import de.axxepta.oxygen.api.BaseXSource;
import de.axxepta.oxygen.tree.TreeListener;
import de.axxepta.oxygen.tree.TreeUtils;
import de.axxepta.oxygen.utils.ConnectionWrapper;
import de.axxepta.oxygen.utils.DialogTools;
import de.axxepta.oxygen.utils.Lang;
import de.axxepta.oxygen.utils.WorkspaceUtils;
import de.axxepta.oxygen.workspace.ArgonOptionPage;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import ro.sync.ecss.extensions.api.component.AuthorComponentFactory;
import ro.sync.exml.workspace.api.PluginWorkspace;
import ro.sync.exml.workspace.api.PluginWorkspaceProvider;
import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

                allResources.set(i, TreeUtils.urlStringFromTreeString(allResources.get(i)));
            }
            showSearchResults(allResources, pathStr, parentFrame, filter);
        }
    }

    // made public for access via AspectJ
    @SuppressWarnings("all")
    public static JPanel createSelectionListPanel(String label, JList resultList) {
        JPanel content = new JPanel(new BorderLayout());
        JLabel foundLabel = new JLabel(label);
        content.add(foundLabel, BorderLayout.NORTH);

        resultList.setLayoutOrientation(JList.VERTICAL);
        resultList.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
        JScrollPane resultPane = new JScrollPane(resultList);
        resultPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        resultPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
        content.add(resultPane, BorderLayout.CENTER);

        return content;
    }

    protected static void showSearchResults(List<String> allResources, String pathStr, JFrame parentFrame, String filter) {
        JList<String> resultList = new JList<>(allResources.toArray(new String[allResources.size()]));

        JDialog resultsDialog = DialogTools.getOxygenDialog(parentFrame, Lang.get(Lang.Keys.dlg_foundresources));

        JPanel content = createSelectionListPanel(Lang.get(Lang.Keys.lbl_search1) + filter + Lang.get(Lang.Keys.lbl_search2) +
                pathStr + Lang.get(Lang.Keys.lbl_search3) + " " + allResources.size() + " " + Lang.get(Lang.Keys.lbl_search4), resultList);

        JPanel buttonsPanel = new JPanel();
        JButton openButton = new JButton(
                new OpenListSelectionAction(Lang.get(Lang.Keys.cm_open), resultList, resultsDialog));
        buttonsPanel.add(openButton);
        JButton checkOutButton = new JButton(
                new CheckOutListSelectionAction(Lang.get(Lang.Keys.cm_checkout), resultList, resultsDialog));
        buttonsPanel.add(checkOutButton);
        JButton cancelButton = new JButton(new CloseDialogAction(Lang.get(Lang.Keys.cm_cancel), resultsDialog));
        buttonsPanel.add(cancelButton);

        content.add(buttonsPanel, BorderLayout.SOUTH);

        DialogTools.wrapAndShow(resultsDialog, content, parentFrame, 700, 300);
    }

    @SuppressWarnings("all")
    public static ArrayList<String> search(TreePath rootPath, int type, boolean restricted,
                                           BaseXSource source, TreePath path, String filter, boolean caseSensitive) {
        ArrayList<String> allResources = new ArrayList<>();
        WorkspaceUtils.setCursor(WorkspaceUtils.WAIT_CURSOR);
        String filterExcludeOption = ArgonOptionPage.getOption(ArgonOptionPage.KEY_BASEX_FILTER_EXCLUDE, false);
        List<String> filterExlucdeDBs = new ArrayList(Arrays.asList(filterExcludeOption.split("\\s*(;|,|\\s)\\s*")));
        switch (type) {
            case SEARCH_ALL: {
                TreePath currentPath = TreeUtils.pathByAddingChildAsStr(rootPath, Lang.get(Lang.Keys.tree_repo));
                allResources.addAll(searchResourcesInPath(BaseXSource.REPO, currentPath, filter, caseSensitive));
//                currentPath = TreeUtils.pathByAddingChildAsStr(rootPath, Lang.get(Lang.Keys.tree_restxq));
//                allResources.addAll(searchResourcesInPath(BaseXSource.RESTXQ, currentPath, filter, caseSensitive));
            }
            case SEARCH_ALL_DBS: {
                List<String> dbList = getDatabases();
                TreePath dbBasePath = TreeUtils.pathByAddingChildAsStr(rootPath, Lang.get(Lang.Keys.tree_DB));
                for (String db : dbList) {
                    if (!restricted || !filterExlucdeDBs.contains(db)) {
                        TreePath currentPath = TreeUtils.pathByAddingChildAsStr(dbBasePath, db);
                        if (currentPath == null) {
                            currentPath = new TreePath(
                                    TreeUtils.insertStrAsNodeLexi(db, (DefaultMutableTreeNode) dbBasePath.getLastPathComponent(), false).
                                            getPath());
                        }
                        allResources.addAll(searchResourcesInPath(BaseXSource.DATABASE, currentPath, filter, caseSensitive));
                    }
                }
                break;
            }
            default: {
                allResources.addAll(searchResourcesInPath(source, path, filter, caseSensitive));
            }
        }
        WorkspaceUtils.setCursor(WorkspaceUtils.DEFAULT_CURSOR);
        return allResources;
    }

    // made public for access via AspectJ
    @SuppressWarnings("all")
    public static List<String> getDatabases() {
        List<BaseXResource> databaseList;
        List<String> databases = new ArrayList<>();
        try {
//            databaseList = ConnectionWrapper.list(BaseXSource.DATABASE, "");
            databaseList = new ArrayList<>();
        } catch (Exception er) {
            logger.debug("Couldn't obtain database list. Error: ", er.getMessage());
            databaseList = new ArrayList<>();
        }
        for (BaseXResource database : databaseList) {
            databases.add(database.getName());
        }
        return databases;
    }

    private static List<String> searchResourcesInPath(BaseXSource source, TreePath path, String filter, boolean caseSensitive) {
        String basePathStr = TreeUtils.resourceFromTreePath(path);
        List<String> allResources = searchResourcesInPathString(source, basePathStr, filter, caseSensitive);
        String searchRoot;
        if (source.equals(BaseXSource.DATABASE))
            searchRoot = TreeUtils.treeStringFromTreePath(TreeUtils.pathToDepth(path, 2)) + "/";
        else
            searchRoot = TreeUtils.treeStringFromTreePath(path) + "/";
        for (int i = 0; i < allResources.size(); i++) {
            allResources.set(i, searchRoot + allResources.get(i));
        }
        return allResources;
    }

    private static List<String> searchResourcesInPathString(BaseXSource source, String basePathStr,
                                                            String filter, boolean caseSensitive) {
        List<String> allResources;
        try {

            allResources = ConnectionWrapper.findFiles(source, basePathStr, filter, caseSensitive);
