All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.reandroid.archive.PathTree Maven / Gradle / Ivy

The newest version!
/*
 *  Copyright (C) 2022 github.com/REAndroid
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.reandroid.archive;

import com.reandroid.json.JSONArray;
import com.reandroid.json.JSONConvert;
import com.reandroid.json.JSONObject;
import com.reandroid.utils.CompareUtil;
import com.reandroid.utils.StringsUtil;
import com.reandroid.utils.collection.ArrayCollection;
import com.reandroid.utils.collection.ComputeIterator;
import com.reandroid.utils.collection.MergingIterator;
import com.reandroid.utils.collection.SingleIterator;

import java.util.*;

public class PathTree implements Comparable>, Iterable>, JSONConvert {
    private T item;
    private String name;
    private PathTree parent;
    private final LinkedHashMap> elementsMap;

    public PathTree(T item, String name){
        this.item = item;
        this.name = name;
        this.elementsMap = new LinkedHashMap<>();
    }
    public PathTree(String name){
        this(null, name);
    }

    public PathTree copy(){
        return copy(getName());
    }
    public PathTree copy(String newName){
        PathTree pathTree = new PathTree<>(getItem(), newName);
        pathTree.setItem(getItem());
        for(PathTree element : this){
            pathTree.add(element.copy());
        }
        return pathTree;
    }
    public void setName(String name){
        String old = this.name;
        if(old.equals(name)){
            return;
        }
        this.name = name;
        PathTree parent = this.parent;
        if(parent != null){
            parent.elementsMap.remove(old);
            parent.elementsMap.put(name, this);
        }
    }

    public void sort(){
        sort(true);
    }
    public void sort(boolean recursive){
        sort(CompareUtil.getComparableComparator(), recursive);
    }
    @SuppressWarnings("unchecked")
    public void sort(Comparator> comparator, boolean recursive){
        LinkedHashMap> elementsMap = this.elementsMap;
        if(elementsMap.size() == 0){
            return;
        }
        PathTree[] elements = elementsMap.values().toArray(new PathTree[0]);
        Arrays.sort(elements, comparator);
        elementsMap.clear();
        for(PathTree pathTree : elements){
            elementsMap.put(pathTree.getName(), (PathTree) pathTree);
        }
        if(!recursive){
            return;
        }
        for(PathTree pathTree : elements){
            pathTree.sort(comparator, true);
        }
    }
    public List> toList(){
        return ArrayCollection.of(elementsMap.values());
    }
    @Override
    public Iterator> iterator(){
        return elementsMap.values().iterator();
    }
    public Iterator> getFiles(){
        Iterator>> iteratorIterator = ComputeIterator.of(iterator(),
                pathTree -> {
                    if(pathTree.isFile()){
                        return SingleIterator.of(pathTree);
                    }
                    return pathTree.getFiles();
        });
        return new MergingIterator<>(iteratorIterator);
    }
    public Iterator getFileItems(){
        return ComputeIterator.of(getFiles(), PathTree::getItem);
    }

    public int size(){
        return elementsMap.size();
    }
    public boolean contains(String name){
        return elementsMap.containsKey(name);
    }
    public PathTree remove(String name){
        return elementsMap.remove(name);
    }
    public PathTree getOrCreate(String name){
        PathTree pathTree = get(name);
        if(pathTree == null){
            pathTree = new PathTree<>(name);
            add(pathTree);
        }
        return pathTree;
    }
    public PathTree get(String name){
        return elementsMap.get(name);
    }
    public PathTree find(String path){
        if(path.equals(getName())){
            return this;
        }
        int i = path.indexOf('/');
        if(i >= 0){
            i++;
            String name = path.substring(0, i);
            path = path.substring(i);
            PathTree pathTree = get(name);
            if(pathTree != null && path.length() != 0){
                return pathTree.find(path);
            }
            return pathTree;
        }else if(path.length() > 0){
            return get(path);
        }
        return null;
    }
    public PathTree add(String path, T item){
        int i = path.indexOf('/');
        if(i >= 0){
            i++;
            String name = path.substring(0, i);
            path = path.substring(i);
            PathTree pathTree = getOrCreate(name);
            if(path.length() == 0){
                pathTree.setItemNonNull(item);
                return pathTree;
            }
            return pathTree.add(path, item);
        }else if(path.length() > 0){
            PathTree pathTree = getOrCreate(path);
            pathTree.setItem(item);
            return pathTree;
        }
        return this;
    }
    public boolean add(PathTree element){
        if(element == null){
            return false;
        }
        element.setParent(this);
        this.elementsMap.put(element.getName(), element);
        return true;
    }
    public T getItem() {
        return item;
    }
    public void setItem(T item) {
        this.item = item;
    }
    private void setItemNonNull(T item) {
        if(item != null){
            setItem(item);
        }
    }
    public boolean isDirectory(){
        return getName().endsWith("/");
    }
    public boolean isFile(){
        return !isDirectory();
    }
    public boolean isRoot(){
        return isDirectory() && getParent() == null;
    }
    public String getName() {
        return name;
    }
    public PathTree getParent(){
        return parent;
    }
    public void setParent(PathTree parent) {
        if(parent != this){
            this.parent = parent;
        }
    }

    public int getDepth(){
        int result = 0;
        PathTree parent = this;
        while (parent != null && !parent.isRoot()){
            result ++;
            parent = parent.getParent();
        }
        return result;
    }
    private PathTree[] getParentElements(){
        int length = getDepth();
        PathTree[] results = new PathTree[length];
        PathTree parent = this;
        int i = length - 1;
        while (parent != null && !parent.isRoot()){
            results[i] = parent;
            i --;
            parent = parent.getParent();
        }
        return results;
    }
    public String getPath(){
        StringBuilder builder = new StringBuilder();
        PathTree[] elements = getParentElements();
        for(int i = 0; i < elements.length; i++){
            builder.append(elements[i].getName());
        }
        return builder.toString();
    }

    @Override
    public int compareTo(PathTree pathTree) {
        boolean is_directory = this.isDirectory();
        if(is_directory == pathTree.isDirectory()){
            String name1 = this.getName();
            String name2 = pathTree.getName();
            if(is_directory){
                name1 = name1.substring(0, name1.length() - 1);
                name2 = name2.substring(0, name2.length() - 1);
            }
            name1 = StringsUtil.toLowercase(name1);
            name2 = StringsUtil.toLowercase(name2);
            return name1.compareTo(name2);
        }
        return is_directory ? -1 : 1;
    }
    @Override
    public void fromJson(JSONObject jsonObject){
        JSONArray jsonArray = jsonObject.optJSONArray(NAME_elements);
        if(jsonArray == null){
            return;
        }
        int count = jsonArray.length();
        for(int i = 0; i < count; i++){
            JSONObject child = jsonArray.getJSONObject(i);
            String path = child.optString(NAME_path, "");
            String name = getName(path);
            PathTree pathTree = getOrCreate(name);
            pathTree.fromJson(child);
        }
    }
    @Override
    public JSONObject toJson(){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put(NAME_path, getPath());
        JSONArray jsonArray = new JSONArray();
        for (PathTree pathTree : this) {
            jsonArray.put(pathTree.toJson());
        }
        if(!jsonArray.isEmpty()){
            jsonObject.put(NAME_elements, jsonArray);
        }
        return jsonObject;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (!(obj instanceof PathTree)) {
            return false;
        }
        PathTree pathTree = (PathTree) obj;
        return Objects.equals(getName(), pathTree.getName());
    }

    @Override
    public int hashCode() {
        return getName().hashCode();
    }

    @Override
    public String toString() {
        return getPath();
    }

    public static PathTree newRoot(){
        return new PathTree<>("/");
    }

    public static Iterator sortPaths(Iterator iterator){
        PathTree pathTree = newRoot();
        while (iterator.hasNext()){
            String path = iterator.next();
            pathTree.add(path, path);
        }
        pathTree.sort();
        return pathTree.getFileItems();
    }
    private static String getName(String path){
        int i = path.length();
        if(i < 2){
            return path;
        }
        i --;
        boolean hasPostfix = false;
        if(path.charAt(i) == '/'){
            path = path.substring(0, i);
            hasPostfix = true;
        }
        i = path.lastIndexOf('/');
        if(i >= 0){
            i++;
            path = path.substring(i);
        }
        if(hasPostfix){
            path = path + '/';
        }
        return path;
    }

    public static final String NAME_path = "path";
    public static final String NAME_elements = "elements";

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy